只有累積,沒有奇蹟

顯示具有 Web API 標籤的文章。 顯示所有文章
顯示具有 Web API 標籤的文章。 顯示所有文章

2022年4月28日 星期四

[WEB API] Swagger - 在 Headers 中新增 API Token 驗證

問題
在開發 API 時都會在網站加上 API Token 機制,當收到一個 Request 請求時 API 會驗證 Token 的正確性,確認請求參數中的 Token 是否是有效 / 已授權 / 有沒有過期或是用來當 SSO (Single sign-on) 的使用,驗證無誤後才會進入接口的邏輯處理目前公司內部 API 專案也有驗證 Token 的設計之前文章介紹了 Swagger 基本使用 發現在線上文件進行 API 測試沒有 Token 的話根本無法測試,此篇記錄如果遇到此問題時該如何解決

解決方案
Swagger 在產生 API 接口會將參數 (Model) 資訊顯示在 html 文件,但如果驗證 Token 機制是在 Header時所生成的 Web API 文件就不會生成在網頁上,寫了一個簡單的範例專案讓大家比較好了解 (僅示意,相信寫法上有更多好的驗證機制)如下圖Code 內容所示,程式碼在進入時就檢查 Request Header 是否有提供 Token 參數,此時使用 Swagger 就是沒有地方可以輸入 Token 參數,因此測試就會因為不符合 Token 驗證會一直爆炸
 
該如何解決呢? 在 Swashbuckle 是很容易擴充的,可以透過加入 IOperationFilter 達到在線上文件新增驗證 Header 的需求,更符合測試上的情境,以下為研究後的小小心得

新增類別並實作 IOperationFilter 
以範例程式為例新增 HeaderTokenOperationFilter 類別並實作 IOperationFilter 介面中的方法 Apply
public class HeaderTokenOperationFilter : IOperationFilter
{
    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
    {
 if (operation.parameters == null)
  operation.parameters = new List();

 operation.parameters.Add(new Parameter
 {
  name = "Token",
  @in = "header", //query
  type = "string",
  description = "User Token In Header",
  required = true
 });
    }
}

程式說明 : 
  • Line 10 : 要加入的 Parameter 名稱
  • Line 11 : 請求時所要放的位置,此範例是在 Header,也可以放在 QueryString
  • Line 12 : 參數型態
  • Line 13 : Parameter 說明
  • Line 14 : 是否必填
設定 SwaggerConfig
開啟 SwaggerConfig.cs 檔案加入下列程式
驗證
重新開啟專案,發現 Swagger 已經有 Token 參數可以提供輸入並會顯示為必填欄位
為了驗證是否真的有在 Request 的 Headers 帶 Token 參數,可以透過 Chrome F12 來觀察是否有帶正確的 Token 參數 : F12 > Network > Headers 
驗證無誤,打完收工

完整 Sample
完整的 Code 有需要請自行服用
    public class HomeController : ApiController
    {
        public string _userSsoToken = "1aa2a116-876e-464b-bdaf-d6d3adaeb4e4";
        
        /// 
        /// 取得使用者金額
        /// 
        /// 
        [HttpPost]
        [Route("GetMoney")]
        [SwaggerRequestExample(typeof(MemberUser), typeof(MemberUserExample))]
        public IHttpActionResult GetMoney(MemberUser input)
        {
            var userInfo = new UserInfo();
            
            // 檢查 Header 是否有 token
            if (Request.Headers.Contains("Token"))
            {
                string token = Request.Headers.GetValues("Token").First();

                if (token == _userSsoToken)
                {
                    // 驗證無誤 回傳資料
                    if (input.UserId == 9487)
                    {
                        GetUserInfo(userInfo);
                    }
                }
                else
                {
                    // 驗證錯誤
                    TokenError(userInfo);
                }

                userInfo.Token = token;
            }
            
            return Ok(userInfo);
        }

        private static void TokenError(UserInfo userInfo)
        {
            userInfo.Code = "999";
            userInfo.Message = "Token error";
        }

        private static void GetUserInfo(UserInfo userInfo)
        {
            userInfo.Code = "000";
            userInfo.Message = "Success";
            userInfo.UserId = "9487";
            userInfo.Name = "marcus";
            userInfo.Money = "1000";
        }
    }
    
    internal class UserInfo
    {
        public string UserId { get; set; }
        public string Name { get; set; }
        public string Money { get; set; }
        public string Code { get; set; }
        public string Message { get; set; }
        public string Token { get; set; }
    }

    public class MemberUser
    {
        public int UserId { get; set; }
    }

    public class MemberUserExample : IExamplesProvider
    {
        public object GetExamples()
        {
            return new MemberUser
            {
                UserId = 9487,
            };
        }
    }
    public class HeaderTokenOperationFilter : IOperationFilter
    {
        public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
        {
            if (operation.parameters == null)
                operation.parameters = new List();

            operation.parameters.Add(new Parameter
            {
                name = "Token",
                @in = "header",
                type = "string",
                description = "User Token In Header",
                required = true
            });
        }
    }
    參考
    add-an-authorization-header-to-your-swagger-ui-with-swashbuckle
    .NET -Swagger Web API for Basic Authentication

    2022年4月10日 星期日

    [WEBAPI] Swagger - 用 Swashbuckle.Examples 加上有意義的測試數據

    問題
    Swagger 是一個可以將 WebAPI 快速文件化的套件,產生出來的線上文件除了可以列出 API 詳細資料外還可以直接在網頁上進行測試的動作,對開發者和接 API 的使用者來說十分方便上一篇文章介紹了 Swagger 基本使用 說明最近想要在公司內部推廣使用 Swagger 服務,資深同事提到過去有陣子曾經使用過 Swagger 服務但  每次要使用 API 接口服務時參數 (params) 資訊都要重新輸入 ,有點麻煩用一陣子之後大家就回去使用 Postman 了,了解後發現的確在測試時會花時間在輸入測試資料,如果測試環境測試資料都是固定的,就可省下輸入資料的時間更可避免 key 錯資料的狀況發生 ( 參考下方 gif 檔案)這邊文章記錄解決此問題的過程
    解決方案
    Swagger 在產生 API 接口的 Model 時取得該物件的 properties 及其對應型別,將其物件資訊顯示在 html文件但不會生成 "可以測試的真實數據 (或是你想要的)" 資料,也就是說替換下圖的紅色框框資料,讓它是有意義的資料搜尋後發現可以使用 Swashbuckle.Examples 來滿足我們小小的需求以下整理研究後的步驟與使用說明

    安裝 Swashbuckle.Examples
    Step 1. 開啟 nuget > 輸入 Swashbuckle.Examples 並下載安裝
    Step 2. 目前最新版是 3.10.0 且不會額外下載其他特別的 dll > 下一步
    Step 3. 可以到專案參考是否有 Swashbuckle.Examples dll,有的話就是下載完成

    實作 Request Sample
    接下來在 Method 上加上 SwaggerRequestExample Attribute第一個參數是原本的 Model第二個參數是範例 Model 名稱以範例專案的例子來說Login 接口第一個參數為 User (原本的 Model) 第二個參數 UserExample (新 Model)
    [SwaggerRequestExample(typeof(Users), typeof(UserExample))]
    public IHttpActionResult Login(Users input) 
    接者新增 UserExample 類別並實作 IExamplesProvider 介面,並將我們指定的測試資料定義在該介面的 GetExample 方法中
    public class UserExample : IExamplesProvider
    {
        public object GetExamples()
        {
     return new Users
     {
      Account = "marcus",
      Password = "123456",
      Key = 9487,
     };
        }
    }
    
    完整的 Code 請參考
    public class HomeController : ApiController
    {   
        [Route("Login")]
        [SwaggerRequestExample(typeof(Users), typeof(UserExample))]
        public IHttpActionResult Login(Users input)
        {
         var rep = new ResponseObject();
    
     if (input.Account == "marcus" 
      && input.Password == "123456" 
      && input.Key == 9487)
     {
      rep.Code = "000";
      rep.Message = "Success";
      rep.Token = Guid.NewGuid();
     }
     else
     {
      rep.Code = "999";
      rep.Message = "Please check your input params";
     }
    
     return Ok(rep);
        }
    }
    
    public class Users
    {
        public string Password { get; set; }
        public string Account { get; set; }
        public int Key { get; set; }
    }
    
    public class UserExample : IExamplesProvider
    {
        public object GetExamples()
        {
     return new Users
     {
      Account = "marcus",
      Password = "123456",
      Key = 9487,
     };
        }
    }
    
    public class ResponseObject
    {
        public string Code { get; set; }
        public string Message { get; set; }
        public Guid Token { get; set; }
    }
    
    設定 SwaggerConfig
    安裝完 Swagger.example package,在 Code 指定好需要產生的 example 物件,下一步是要在 Swagger 設定 OperationFilter開啟 SwaggerConfig.cs 檔案加入下列程式

    打完收工 
    透過以上設定,在重新開啟 Swagger 就可以發現 example model 已生效,省下了輸入 API 參數的時間可以更專注的在測試 / 驗證接口正確性,提升效率早點下班回家為了證明哥沒有在唬爛調整後的畫面如下
    Swashbuckle.Examples 在使用上簡單容易上手,但除了可以透過此套件定義 Example Request Model 之外,官網文件上與有提到可以設定 Example Response Model、Description、Authorization...等更多資訊,也支持 .NET Core 版本,如果有需要各位大大也可以自行研究看看
    Summary
    這問題聽到當下嚇到吃手手,江湖上常聽到攻城屍很懶惰但沒想到懶到這程度,但仔細了解後發現問題確實存在,且驗證後發現,在此範例三個參數使用完整整省去一半的時間 18 sec > 9sec想到之前參加研討會講師所講的,懶是一個美德否則會局限自己的成長

    參考
    Swashbuckle.Examples
    Swashbuckle Pro Tips for ASP.NET Web API – Example(s) Using AutoFixture
    Swagger for Web API Document – Part Ⅱ

    2021年6月13日 星期日

    [NETCore] ASP.NET Core 中的例外處理方式

    前言
    錯誤處理一直是開發中的重要環節之一,如果在程式發生異常錯誤的當下有效的將錯誤訊息完整的記錄下來,可以大大的節省 debug 的時間與效率,反過來如果在開發時沒有考慮到異常處理的機制,可能在發生問題時要找到錯誤的原因難度就會提高,因此在開發時必須要考慮到異常處理的機制,過去公司都會將 exception 訊息透過推(push)或是拉(pull)的方式傳送到 Logstash 再搭配 Elasticsearch 與 Kibana 搜尋到相對應的錯誤訊息或是 Log。這篇就簡單分享在 ASP.NET Core 中如何使用 ExceptionFilter 以及 Middleware 捕捉異常紀錄的方式,內容若有問題歡迎提出來一起討論。

    開個 Error 給他
    首先在 Visual Studio 2019 建立 ASP.NET Core API 專案
    為了模擬例外狀況的發生,在預設提供的 WeatherForecastController.cs 中直接加上 throw 一個訊息為 "我是醬爆,我要爆了 !" 的 exception,代碼如下
    [HttpGet]
    public IEnumerable Get()
    {
        throw new Exception("我是醬爆,我要爆了!!!");
    
        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        })
        .ToArray();
    }
    
    接著在執行應用程式,可以看到應用程式開啟後即噴出異常訊息

    使用 Exception Filter
    首先為了更模擬一般開發情境,建立 API 共用回傳的 Model 與自訂客製的例外 CustomerException 等兩個 model,代碼如下
    public class ApiResponse
    {
        public DateTimeOffset Timestamp { get; set; }
        public string Message { get; set; }
        public string Result { get; set; }
    }
    
    public class CustomerException: Exception
    {
        private readonly Exception _exception;
    }
    
    在 ASP.NET Core 中如果要自訂錯誤機制 exception Filter 必須透過實作 IExceptionFilter 或是 IAsyncExceptionFilter 介面,差異只是 IAsyncExceptionFilter 實現非同步等待(看需求),接著建立例外發生時要用到的類別名為 BombExceptionFilter ,類別中實作 IExceptionFilter 中的 OnException 方法裡面定義當例外發生時要做的處理機制
    public class BombExceptionFilter : IExceptionFilter
    {
        private ILogger _log;
    
        public BombExceptionFilter(ILogger log)
        {
            _log = log;
        }
    
        public void OnException(ExceptionContext context)
        {
            var status = HttpStatusCode.InternalServerError;
            var message = string.Empty;
    
            var exceptionType = context.Exception.GetType();
            if (exceptionType == typeof(CustomerException))
            {
                message = context.Exception.Message;
            }
            else
            {
                message = "something wrong";
            }
    
            // log 
            _log.LogError(context.Exception, $"Ex massage: {message}, StackTrace: {context.Exception.StackTrace}", context.Exception);
    
            // 設定 exception 已處理完畢
            context.ExceptionHandled = true;
            var response = context.HttpContext.Response;
            response.StatusCode = (int)status;
            response.ContentType = "application/json";
            
            context.Result = new ObjectResult(new ApiResponse { Timestamp = DateTimeOffset.UtcNow, Message = message, Result = "我出包了,請給我一點時間" });
        }
    }
    
    OnException 中邏輯為當發生例外時,會根據發生例外的種類 exception Type 來取得回傳的錯誤訊息並定義再回傳的 message 屬性中;另外也在第38行將錯誤紀錄在 log 中,可搭配習慣的 log 解決方案,像是 log4net、serilog 看團隊習慣決定;使用 apiResponse 類別作為回傳的格式,其中定義了 timestamp、Message 及 result 等屬性,當發生錯誤時在 result 會定義 "我出包了,請再給我一點時間" 訊息告知呼叫 client 端。

    接著在 startUp.cs 的 ConfigureServices 區塊加上 BombExceptionFilter 下列代碼
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllers();
    
        services.AddScoped<BombExceptionFilter>();
    }
    
    最後一步在 controller 中的 action 加上 BombExceptionFilter attribute
    [ServiceFilter(typeof(BombExceptionFilter))]
    [HttpGet]
    public IEnumerable Get()
    {
        throw new Exception("我是醬爆,我要爆了!!!");
    
        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        })
        .ToArray();
    }
    
    接著我們 run 應用程式看當發生錯誤時自定義的 BombExceptionFilter exception Filter 是否有生效,可以看到結果如下設定成功
    有關在 ASP.NET Core 中更詳細的 exception filters 可以參考 MSDN 文件

    使用 Middleware
    Middleware 與 exception 相比就簡單許多,在 如何在 ASP.NET Core Middleware 加上單元測試 Unititest 文章中有詳細介紹關於 middleware 基本使用方式,這裡就不在多加說明,新增 CustomerExceptionMiddleware 的中介層來處理 exception 的邏輯,代碼如下
    public class CustomerExceptionMiddleware 
    {
        private readonly RequestDelegate _next;
        private readonly ILogger _logger;
    
        public CustomerExceptionMiddleware(RequestDelegate next, ILogger logger)
        {
            _next = next;
            _logger = logger;
        }
    
        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            catch (Exception ex)
            {
                await HandleException(context, ex);
            }
        }
    
        private Task HandleException(HttpContext context, Exception ex)
        {
            context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
            context.Response.ContentType = "application/json";
            var message = ex.GetType() == typeof(CustomerException) ? ex.Message : "something wrong";
    
            // log 
            _logger.LogError(ex, $"Ex massage: {message}, StackTrace: {ex.StackTrace}", ex);
    
            var result = JsonConvert.SerializeObject(new ApiResponse
                {Timestamp = DateTimeOffset.UtcNow, Message = message, Result = "我出包了(Middleware)"});
            return context.Response.WriteAsync(result);
        }
    }
    
    在代碼中加上 try/catch 將發生錯誤的 exception 捕捉起來,並設定回傳 statusCode 為 IIS Server Error 以及與上述 exception filter 相同將錯誤記錄在 log 中,另外將錯誤的 result 設定為 "我出包了(Middleware)" 區別是 middleware catch 到的錯誤,接著新增擴充方法 UseCustomerExceptionMiddleware 方便在 startup 使用
    public static class ApplicationBuilderExtension
    {
        public static IApplicationBuilder UseCustomerExceptionMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware();
        }
    }
    
    修改 startup.cs 將稍早的 BombExceptionFilter 註解,Configure 代碼加上 UseCustomerExceptionMiddleware 方法
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
    
        ...
        app.UseCustomerExceptionMiddleware();
        ...
    }
    
    重新執行應用程式,可以發現當 application 發生 error 的時候有 catch 到錯誤訊息
    宣告使用 middleware 成功 !

    感想
    以上針對 exception 在 ASP.NET Core 的處理方式,分別是使用 exception filters 與 middleware 兩種方法,另外還可以使用內建的 UseExceptionHandler 方法達到類似的效果,詳細可以參考 Cash 大大 ASP.NET Core 使用內建的 ExceptionHandler Middleware 實作全站 Exception 處理的文章說明,這裡就不再班門弄斧的多加說明;還有在開發中有需要注意順序性的問題,可以透過 MSDN 的圖片了解到 middleware 與 filter 的執行順序,避免認知錯誤造成自己在開發上時間的浪費,希望這篇文章可以幫助到需要的朋友 :)

    參考
    ASP.NET Core Web API exception handling
    ASP.NET Core 中的篩選條件
    Asp.NetCore依赖注入和管道方式的异常处理及日志记录
    ASP.NET Core 使用內建的 ExceptionHandler Middleware 實作全站 Exception 處理
    [鐵人賽 Day17] ASP.NET Core 2 系列 - 例外處理 (Exception Handler)
    Using ExceptionFilter for exception handling in AspNet Core Web API

    2021年5月30日 星期日

    [NETCore] ASP.NET Core 中加入 API 版本控制

    前言
    在開發 API 時可能會因為代碼調整或是架構的演進,相同的 API 接口可能會有新的版本出現,為了不影響舊的呼叫端程式邏輯運作,就需要在代碼中加上新舊版本的對應來解決 API 版本問題,或許為了解決 API 版本問題可以有很多種不同的解法,在 ASP.NET Core 中可以透過  Microsoft.AspNetCore.Mvc.Versioning  來解決此問題,這篇就來分享一下有關Microsoft.AspNetCore.Mvc.Versioning 套件的安裝與基本使用,若有問題或是錯誤的地方歡迎網路的高手大大給予指導

    安裝
    首先直接透過專案的代碼可以方便大家可以更快的了解,起手式先建立一個 ASP.NET Core API 專案來作示範
    建立完專案之後第一步是開啟開啟 Nuget Package Mnage 輸入 Microsoft.AspNetCore.Mvc.Versioning  搜尋,安裝目前最新版的套件
    或是透過 Nuget Package Console 輸入下列指令
    Install-Package Microsoft.AspNetCore.Mvc.Versioning
    安裝完畢之後到專案檔底下確認是否有安裝成功
    <ItemGroup>    
        <PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="3.1.3" />    
    </ItemGroup>

    設定 
    接著開啟專案中 Startup.cs 的 ConfigureServices 加上下列代碼
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        services.AddApiVersioning(o => {
            o.ReportApiVersions = true;
            o.AssumeDefaultVersionWhenUnspecified = true;
            o.DefaultApiVersion = new ApiVersion(1, 0);
        });
    }
    簡單說明一下設定所代表的含意及意義

    ReportApiVersions

    支援在 API Response Header 中加入 API 支援的版本,讓呼叫端知道目前版本有哪些,舉例來說開啟設定後如下,可以看到目前 API 支援的版本有 1.0 及 2.0 兩種版本

    AssumeDefaultVersionWhenUnspecified
    當發送的請求未指定 api-version 版本號時,是否需要啟用預設版本號。如果設定為 false 也未指定版本耗時則會出現錯誤訊息 An API version is required, but was not specified.

    DefaultApiVersion
    預設 API 版本號碼

    使用 URL Querystring 指定版本
    在此框架中使用  ApiVersion  來區分不同版本 API,接著為了要測試不同版本 API 回傳與設定,在 Controller 中加入下列代碼來驗證
    using Microsoft.AspNetCore.Mvc;
    
    namespace NetCoreWebAPIVersion.Controllers
    {
        [ApiController]
        [ApiVersion("1.0")]
        [Route("api/[controller]")]
        public class ValuesController : ControllerBase
        {
            [HttpGet]
            public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
        }
    
        [ApiController]
        [ApiVersion("2.0")]
        [Route("api/values")]
        public class Values2Controller : ControllerBase
        {
            [HttpGet]
            public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
        }
    }
    當未指定 API 版本時候,會參考稍早在 startup 中的 AssumeDefaultVersionWhenUnspecified 與 DefaultApiVersion 設定,在此範例中預設為 1.0 版因此可以看到回傳 version 為 1.0

    透過上列代碼,可以在 url 帶入 api-version 參數來指定版本,舉例來說要指定版本為 2.0 則帶入 localhost/api/values?api-version=2.0 

    使用 URL Route 指定版本 
    也支援使用 Route 指定版本號,可以在 Route 加上  Route("api/v{version:api-version}/[controller]  ,根據上述調整做些微調如下
    namespace NetCoreWebAPIVersion.ControllersV2
    {
        [ApiController]
        [ApiVersion("1.0")]
        [Route("api/v{version:apiVersion}/[controller]")]
        public class ValuesController : ControllerBase
        {
            [HttpGet]
            public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
        }
    
        [ApiController]
        [ApiVersion("2.0")]
        [Route("api/v{version:apiVersion}/values")]
        public class Values2Controller : ControllerBase
        {
            [HttpGet]
            public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
        }
    }
    使用方式就很簡單,指定 1.0 版本
    指定 2.0 版本  
    如果需求情境是希望版號加在 Header 中,讓 url 避免透漏過多資訊也乾淨些,則可以在 service 中使用  HeaderApiVersionReader 進行設定,詳細可以參考官網說明。

    設定過期 (棄用) 版本
    在某些情境下可能早期的 API 版本將不在支援,在此框架中就可以透過設定 Deprecated  讓使用端知道,
    舉例來說,下列代碼在 controller 一共有 0.1、1.0以及 2.0 三個版本,其中設定 0.1 版將不在支援,因此在 ApiVersion 中定義 Deprecated = true
    namespace NetCoreWebAPIVersion.ControllersV2
    {
        [ApiController]
        [ApiVersion("0.1", Deprecated =true)]
        [Route("api/v{version:apiVersion}/[controller]")]
        public class Values3Controller : ControllerBase
        {
            [HttpGet]
            public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
        }
    
        [ApiController]
        [ApiVersion("1.0")]
        [Route("api/v{version:apiVersion}/[controller]")]
        public class ValuesController : ControllerBase
        {
            [HttpGet]
            public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
        }
    
        [ApiController]
        [ApiVersion("2.0")]
        [Route("api/v{version:apiVersion}/values")]
        public class Values2Controller : ControllerBase
        {
            [HttpGet]
            public string Get(ApiVersion apiVersion) => $"Controller = {GetType().Name}\nVersion = {apiVersion}";
        }
    }
    在呼叫 API 的 Response Header 中就可以看到目前支援版本為 1.0 與 2.0 兩種,版本 0.1 已過期

    不限版本
    在一些通用的 API 接口是不需要受到版號設定的,例如 Health Check 等資訊,硬是加上版號會讓人使用上更為不便,在此情境可以加上  ApiVersionNeurtal  屬性達到效果,並從 API 版本控制中移除
    [ApiVersionNeutral]
    [Route("api/[controller]")]
    [ApiController]
    public class HealthCheckController : ControllerBase
    {
        public string Get() => "OK";
    }

    感想
    透過以上說明相信對於ASP.NET Core WebApi Version 設定與應用有基本了解,在微軟 GitHub 官方 aspnet-api-versioning 也提供 sample code 範例給開發者了解,也可以發現版本控管框架不只支援 ASP.NET Core 也支援 .NET Framework WebAPI,如果對於細節或是應用想了解更多的話,不坊可以到 GitHub 可以看到更多有興趣的項目,希望這篇介紹可以有幫助到有需要的朋友 :)
    Sample Code Path : sampleCode/NETCoreWebAPIVersioning

    參考
    aspnet-api-versioning
    API Versioning in ASP.net Core
    ASP.NET Core Web API Versioning 的做法

    Copyright © m@rcus 學習筆記 | Powered by Blogger

    Design by Anders Noren | Blogger Theme by NewBloggerThemes.com