從 MVC 到使用 ASP.NET Core 6.0 的最小 API

溪源More發表於2021-10-18

從 MVC 到使用 ASP.NET Core 6.0 的最小 API

https://benfoster.io/blog/mvc-to-minimal-apis-aspnet-6/

2007 年,隨著 ASP.NET MVC 引入了其他語言中變得司空見慣的模型-檢視-控制器模式,併為其提供原生支援,.NET Web 應用程式開發有了極速的發展。

2012 年,也許是由於 ReSTful API 的日益流行,借鑑了 ASP.NET MVC 的許多概念又引入了 ASP.NET Web API,這是對 WCF 的重大改進,使開發人員能夠以更少的儀式構建 HTTP API,。

後來,在 ASP.NET Core 中,用於構建網站和 API 的單一框架,這些框架被統一到了 ASP.NET Core MVC 中。

在 ASP.NET Core MVC 應用程式中,控制器負責接受輸入、執行或編排操作並返回響應。它是一個功能齊全的框架,通過過濾器、內建模型繫結和驗證、約定和基於宣告的行為等提供可擴充套件的管道。對於許多人來說,它是構建現代 HTTP 應用程式的多合一解決方案。

在某些情況下,您可能只需要 MVC 框架的特定功能或具有使 MVC 不受歡迎的效能限制。隨著更多 HTTP 功能作為 ASP.NET Core 中介軟體(例如身份驗證、授權、路由等)出現,無需 MVC 即可構建輕量級 HTTP 應用程式變得更加容易,但通常需要一些功能,否則您必須自己構建,例如作為模型繫結和 HTTP 響應生成。

ASP.NET Core 6.0 旨在通過 Minimal API 彌合這一差距,以更少的儀式提供 ASP.NET MVC 的許多功能。這篇文章提供了有關如何將傳統 MVC 概念轉換為這種構建輕量級 HTTP API 和服務的新方法的分步指南。

在這些示例中,我使用的是 .NET 6.0 預覽 7,為了提供公平和最新的並排比較,我還使用了最新的webapi模板,因為 MVC 還受益於 C# 10 的一些新特性,使事情變得更加“最小化”。

引導

MVC

dotnet new webapi

新的 ASP.NET 模板取消了Startup類並利用了 C# 10 的頂級語句功能,因此我們有一個Program.cs包含所有引導程式碼的檔案:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.

builder.Services.AddControllers();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (builder.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

呼叫builder.Services.AddControllers()負責註冊 MVC 框架依賴項並發現我們的控制器。然後我們呼叫app.MapControllers()註冊我們的控制器路由和 MVC 中介軟體。

最少的API

dotnet new web

ASP.NET Empty 模板對規範的“Hello world”示例使用 Minimal API:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.MapGet("/", () => "Hello World!");

app.Run();

MapGet方法是 Minimal API 擴充套件的一部分。除此之外,它與 MVC 並沒有太大區別(考慮到 HTTPS 重定向和授權中介軟體只是從 Empty 模板中省略而不是隱式啟用)。

定義路由和處理程式

MVC

在 MVC 中,我們有兩種定義路由的方法,一種是通過約定,一種是使用屬性。

基於約定的路由更常用於網站而不是 API,幷包含在mvc模板中。而不是app.MapControllers我們使用:

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

所述pattern指定路線的不同區段,並且允許指定的預設值。引數可以利用 ASP.NET 的路由約束語法來限制接受的值。

對於 API,建議使用基於屬性的路由

通過屬性路由,您可以使用指定 HTTP 動詞和路徑的屬性來裝飾控制器和動作:

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };
    
    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

在啟動時,路由將自動註冊。上面的示例來自預設webapi模板,演示了路由令牌替換。該[Route("[controller]")]屬性將使用/weatherforecast所有路由的字首(或資源)(控制器類名減去“Controller”字尾),無引數[HttpGet]屬性將在資源的根處註冊操作,因此HTTP GET /weatherforecast將命中此操作。

如果我想擴充套件 API 以允許按位置檢索預測,我可以新增以下操作:

[HttpGet("locations/{location}")]
public IEnumerable<WeatherForecast> GetByLocation(string location)
{

}

請求時,/weatherforecast/locations/london該值london將繫結到相應的操作引數。

與它們的 Minimal API 對應物相比,MVC 控制器看起來非常臃腫。但是,值得注意的是,控制器也可以是 POCO(Plain Old CLR Objects)。為了獲得與上面的“Hello World”最小 API 示例相同的結果,我們只需要:

public class RootController
{
    [HttpGet("/")]
    public string Hello() => "Hello World";
}

從這裡你可以看到尤其是當你考慮到你仍然需要一定程度的模組化時,即使使用最小的 API, MVC 也可以是“最小的”,。

最少的API

要使用 Minimal API 定義路由和處理程式,請使用Map(Get|Post|Put|Delete)方法。有趣的是沒有MapPatch方法,但您可以使用MapMethods.

要使用 Minimal API 實現相同的天氣預報示例:

var summaries = new[]{    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"};app.MapGet("/weatherforecast", () =>{    return Enumerable.Range(1, 5).Select(index => new WeatherForecast    {        Date = DateTime.Now.AddDays(index),        TemperatureC = Random.Shared.Next(-20, 55),        Summary = summaries[Random.Shared.Next(summaries.Length)]    })    .ToArray();});app.Run();

與 MVC 示例類似,我們可以將其擴充套件為按位置查詢:

app.MapGet("/weatherforecast/locations/{location}", (string location) =>{});

請注意,在 MVC 和 Minimal API 示例中,我們受益於返回型別到序列化 HTTP 200 (OK) 響應的隱式轉換。稍後我們將介紹兩個框架的更明確的 HTTP 物件模型。

模型繫結

模型繫結是從 HTTP 請求中檢索值並將它們轉換為 .NET 型別的過程。由於我們在上面介紹了繫結路由值,本節將主要關注在請求正文中或通過查詢字串引數接收 JSON 資料。

MVC

在 MVC 中,您可以將 JSON 從請求正文繫結到 .NET 型別,方法是將其作為引數傳遞給您的操作方法並使用[FromBody]屬性對其進行修飾:

[HttpPost("/payments")]public IActionResult Post([FromBody]PaymentRequest request){    }

或者,通過使用[ApiController]屬性裝飾您的控制器,將應用一個約定來繫結主體中的任何複雜型別。

在某些情況下,您可能希望從查詢引數繫結複雜型別。我喜歡為具有多個過濾選項的搜尋端點執行此操作。您可以使用以下[FromQuery]屬性實現此目的:

[HttpGet("/echo")]public IActionResult Search([FromQuery]SearchRequest request){    }

否則,簡單型別將從路由或查詢字串值繫結:

[HttpGet("/portfolios/{id}")]public IActionResult Search(int id, int? page = 1, int? pageSize = 10){    }

/portfolios/10?page=2&pagesize=20將滿足上述操作引數的請求。

上面的示例還通過將可選引數標記為可為空並可選地提供預設值來演示可選引數的使用。

這對於複雜型別的工作方式略有不同。即使將型別設為可空,如果未傳送正文,您將收到 HTTP 415(無效媒體型別)或 400(錯誤請求)響應,具體取決於是否Content-Type設定了標頭。

以前,這種行為只能通過全域性進行MvcOptions.AllowEmptyInputInBodyModelBinding全域性配置,但從 ASP.NET Core 5 開始,它現在可以按請求進行配置:

[HttpPost("/payments")]public IActionResult Post([FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)]PaymentRequest? request){    }

最少的API

Minimal API 中的模型繫結非常相似;您使用您希望從請求中繫結的型別配置您的處理程式委託。複雜型別將從請求正文中自動繫結,而簡單型別將從路由或查詢字串引數中繫結。使用 Minimal API 實現的相同示例如下:

app.MapPost("/payments", (PaymentRequest paymentRequest) => {    });app.MapGet("/portfolios/{id}", (int id, int? page, int? pageSize) => {});

為了指定預設值,您需要傳遞一個方法作為委託,因為 C# 尚不支援內聯 lambda 函式的預設值:

app.MapGet("/search/{id}", Search);app.Run();IResult Search(int id, int? page = 1, int? pageSize = 10){}

[FromQuery]屬性不支援繫結複雜型別。有可用於自定義模型繫結的擴充套件點,我將在後面的文章中介紹。

要支援可選的請求引數,您可以應用與[FromBody]MVC相同的屬性,指定EmptyBodyBehavior

app.MapPost("/payments", ([FromBody(EmptyBodyBehavior = EmptyBodyBehavior.Allow)]PaymentRequest? paymentRequest]) => {});

HTTP 響應

MVC 和 Minimal API 都會自動將您的返回型別序列化到響應正文並返回 HTTP 200 (OK) 響應,例如:

// MVC[HttpPost("/echo")]public EchoRequest Echo(EchoRequest echo) => echo;// Minimal APIapp.MapPost("/echo", (EchoRequest echo) => echo);

您還可以返回voidTask返回一個空的 HTTP 200 (OK) 響應:

// MVC[HttpPost("/echo")]public void Echo(EchoRequest echo) => {};// Minimal APIapp.MapPost("/echo", (EchoRequest echo) => {});

除了隱式轉換之外,MVC 和 Minimal API 都有一個豐富的 HTTP 響應物件模型,涵蓋了最常見的 HTTP 響應。

MVC

在 MVC 中,您可以返回IActionResult並使用許多內建實現,例如AcceptedResult. 如果您是從ControllerBase那裡派生控制器的,那麼大多數響應型別都可以使用輔助方法:

[HttpDelete("/projects/{id}")]public IActionResult Delete(int id){    return Accepted();}

最少的API

使用 Minimal API,我們可以返回IResult. 在Results靜態類可以很容易地產生了一些內建的響應型別:

app.MapDelete("/projects/{id}", (int id) =>{    return Results.Accepted();});

依賴注入

MVC

要將依賴項注入 MVC 控制器,我們通常使用建構函式注入,其中所需的型別(或更常見的是它們的底層介面)作為建構函式引數提供:

public class CacheController : ControllerBase{    private readonly ICache _cache;    public CacheController(ICache cache)    {        _cache = cache;    }    [HttpDelete("/cache/{id}")]    public async Task<IActionResult> Delete(string id)    {        await _cache.Delete(id);        return Accepted();    }}

依賴項在啟動時註冊(現在預設在 Program.cs 中):

builder.Services.AddScoped<ICache, MemoryCache>();

使用範圍生命週期註冊的服務將在 MVC 應用程式中按 HTTP 請求建立。

最少的API

使用 Minimal API,我們仍然可以從依賴注入中受益,但不是使用建構函式注入,而是在處理程式委託中將依賴作為引數傳遞:

app.MapDelete("/cache/{id}", async (string id, ICache cache) =>{    await cache.Delete(id);    return Results.Accepted();});

這種方法更純粹,可以使測試更容易。不利的一面是,一旦您獲得多個依賴項,您的處理程式定義就會變得非常嘈雜。

最後,雖然依賴在 內本地宣告的依賴項可能很誘人Program.cs,但這不僅會使測試變得困難,而且還會導致範圍問題。我建議儘可能利用 DI 容器,即使是單例依賴。

語境

您的 API 可能需要訪問有關 HTTP 請求的其他資訊,例如當前使用者的標頭或詳細資訊。MVC 和 Minimal API 都構建在您熟悉的相同 ASP.NET Core HTTP 抽象之上。

MVC

在MVC中,獲得您的控制器時,從ControllerBase您可以訪問HttpContextHttpRequestHttpResponse和當前使用者(ClaimsPrincipal從基類屬性):

[HttpGet]public IEnumerable<WeatherForecast> Get(){    if (Request.Headers.TryGetValue("some header", out var headerValue))    {    }    bool isSpecialUser = User.Identity.IsAuthenticated         && User.HasClaim("special");

如果您的控制器是一個簡單的 POCO 並且不是派生自ControllerBase您,則需要使用建構函式注入來注入IHttpContextAccessor您的控制器或直接訪問請求、響應和使用者,請為這些型別執行一些 DI 連線。如果 POCO 控制器可以利用類似於下面描述的 Minimal API 的方法注入,那就太好了。

最少的API

使用 Minimal API,您可以通過將以下型別之一作為引數傳遞給處理程式委託來訪問相同的上下文資訊:

  • HttpContext
  • HttpRequest
  • HttpResponse
  • ClaimsPrincipal
  • CancellationToken (請求中止)
app.MapGet("/hello", (ClaimsPrincipal user) => {    return "Hello " + user.FindFirstValue("sub");});

連結生成

在某些情況下,您需要生成指向 API 其他部分的連結。在 ASP.NET Core 中,我們可以依靠現有的 HTTP 和路由基礎結構來避免對 URI 元件進行硬編碼。要生成到已知路線的連結,我們首先需要一種方法來識別它們。

MVC

在 MVC 中,我們可以將一個Name屬性傳遞給我們用來裝飾控制器操作的路由屬性,例如:

[HttpGet("products/{id}", Name = "get_product")]public IActionResult GetProduct(int id){}

然後我們可以使用IUrlHelper生成指向該路由的連結:

[HttpPost("products", Name = "create_product")]public IActionResult CreateProduct(CreateProduct command){    var product = Create(command);    return Created(Url.Link("get_product", new { id = product.Id }));}

請注意路由的路由引數(get_product在本例中為 ID)是如何作為匿名物件傳遞的。

IUrlHelper可通過Url酒店獲得ControllerBase。或者,您可以將它注入到您的類中,前提是您HTTP 範圍內。

最少的API

使用 Minimal API,您可以通過附加後設資料來命名端點:

app.MapGet("/products/{id}", (int id) =>{    return Results.Ok();}).WithMetadata(new EndpointNameMetadata("get_product"));

上述內容的簡寫版本WithName將在未來版本中提供。

還有一個出色的建議是在傳遞方法組而不是內聯 lambda 時隱式生成端點名稱。從上面的問題:

// These endpoints have their name set automaticallyapp.MapGet("/todos/{id}", GetTodoById);async Task<IResult> GetTodoById(int id, TodoDb db){    return await db.Todos.FindAsync(id)        is Todo todo            ? Results.Ok(todo)            : Results.NotFound();};

更新:David Fowler 確認這將在 .NET 6 rc1 中可用

命名端點後,您可以注入LinkGenerator處理程式以生成連結:

app.MapPost("payments", async (HttpContext httpContext, IMediator mediator, LinkGenerator links, PaymentRequest payment) =>{    var result = await mediator.Send(payment);    return result.Match(        invalidRequest => invalidRequest.ToValidationProblem(),        success => Results.Created(links.GetUriByName(httpContext, "get_payment", new { id = success.Id})!, payment)    );})

一些內建的 Result 助手代表你處理這個樣板。同樣的例子,簡化為Results.CreatedAtRoute

app.MapPost("payments", async (HttpContext httpContext, IMediator mediator, PaymentRequest payment) =>{    var result = await mediator.Send(payment);    return result.Match(        invalidRequest => invalidRequest.ToValidationProblem(),        success => Results.CreatedAtRoute("get_payment", new { id = success.Id }, success);    );})

驗證

MVC

輸入驗證是任何 API 的重要組成部分。MVC 在 ASP.NET 之上新增的功能之一是模型狀態。從文件

模型狀態表示來自兩個子系統的錯誤:模型繫結和模型驗證。源自模型繫結的錯誤通常是資料轉換錯誤。

MVC 還包括對通過屬性進行驗證的內建支援,例如:

public class PaymentRequest{    [Required]    public int? Amount { get; set; }        [Required]    [StringLength(3)]    public string Currency { get; set; }}

提示:一個流行的選擇是為Fluent Validation替換基於預設屬性的驗證。

繫結到此模型型別時,任何驗證錯誤都會自動新增到模型狀態。在控制器中,我們可以檢查它並採取適當的措施:

public IActionResult Post(PaymentRequest paymentRequest){    if (!ModelState.IsValid)    {        // return validation error    }    // otherwise process}

事實上,如果我們用[ApiController]約定來裝飾我們的控制器,我們甚至不需要做上面的事情。這將過濾器應用於 MVC 管道,該過濾器將驗證任何請求的輸入並在必要時返回問題詳細資訊響應。

{    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",    "title": "One or more validation errors occurred.",    "status": 400,    "traceId": "00-293242b60c05924743847956126b31fe-a1b01281b398430d-00",    "errors": {        "Amount": [            "The Amount field is required."        ],        "Currency": [            "The Currency field is required."        ]    }}

這是 MVC 過濾器管道如何從您的應用程式中刪除重複的一個很好的例子。過濾器可以訪問您在 ASP.NET 中介軟體中沒有的其他上下文。這是允許內建驗證中介軟體自動執行的原因,因為它能夠模型繫結發生執行。

最少的API

就目前而言,Minimal API 沒有任何內建的驗證支援。但是,您當然可以自由地推出自己的產品。

Damian Edwards 建立了MinimalValidation,這是一個利用類似於預設 MVC 驗證的驗證屬性的小型庫:

app.MapPost("/widgets", (Widget widget) =>    !MinimalValidation.TryValidate(widget, out var errors)        ? Results.BadRequest(errors)        : Results.Created($"/widgets/{widget.Name}", widget));app.Run();class Widget{    [Required, MinLength(3)]    public string? Name { get; set; }    public override string? ToString() => Name;}

您可以在此處找到更多示例。

我個人更喜歡使用Fluent Validation通常用這個庫替換 MVC 中基於屬性的驗證。

下面是使用 Fluent Validation 和最少 API 的示例:

builder.Services.AddValidatorsFromAssemblyContaining<PaymentRequest>(lifetime: ServiceLifetime.Scoped);var app = builder.Build();app.MapPost("payments", async (IValidator<PaymentRequest> validator, PaymentRequest paymentRequest) =>{    ValidationResult validationResult = validator.Validate(paymentRequest);    if (!validationResult.IsValid)    {        return Results.ValidationProblem(validationResult.ToDictionary());    }    // otherwise process});// URL generation?app.Run();public record PaymentRequest(int? Amount, string Currency){    public class Validator : AbstractValidator<PaymentRequest>    {        public Validator()        {            RuleFor(x => x.Amount).NotNull().WithMessage("amount_required");            RuleFor(x => x.Currency).Length(3).WithMessage("currency_invalid");        }    }}public static class ValidationExtensions{    public static IDictionary<string, string[]> ToDictionary(this ValidationResult validationResult)        => validationResult.Errors                .GroupBy(x => x.PropertyName)                .ToDictionary(                    g => g.Key,                    g => g.Select(x => x.ErrorMessage).ToArray()                );}

注意:FV 驗證器不需要巢狀在它們的目標型別中。這只是個人喜好。

在這裡,我利用 Fluent Validation 的程式集掃描功能來定位我的驗證器。或者,我可以IValidator<T>顯式註冊實現。無論哪種方式,這都意味著我的驗證器可以提供給我的處理程式,我可以驗證傳入的型別。

這裡的一個缺點是您可能最終會在每個處理程式中編寫相同的樣板驗證檢查。可以通過一些重構來減少它,但是沒有可以訪問繫結模型的預處理程式鉤子,我們不能像使用 MVC 過濾器那樣輕鬆地短路請求。我將在稍後的部落格文章中介紹一些替代方法。

JSON 序列化

您可能需要自定義預設的 JSON 序列化設定以滿足您的需求或 API 樣式指南。例如,預設設定將欄位名稱序列化為駝峰式大小寫(即firstName),但我們的 API 標準要求所有 API 都使用蛇形大小寫(即first_name)。

ASP.NET 6.0 使用 System.Text.Json 處理 JSON,自定義選項在此處有詳細說明。

MVC

在 MVC 中,您可以通過AddJsonOptions擴充套件自定義 JSON :

services.AddControllers()    .AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = new SnakeCaseNamingPolicy());

注意:開箱即用仍不支援蛇形命名法(Snake casing,譯者按:當今許多程式語言都建議在某些情況下使用類似蛇的命名法,對於單個字元或單詞(例如A,PYTHON,BOY),當將它們用作變數名時,大致所有小寫字母,全部大寫字母和首字母大寫字母。但是,程式語言通常需要使用多個單詞或符號來表示變數名中更豐富的含義。 英語習慣於使用空格分隔單詞,但是這種用法會給程式語言帶來麻煩,因此程式設計師建立了其他方法,蛇形命名法就是用下劃線分隔兩個字元,使其可讀性更強)。您可以在此處找到上述策略的原始碼。

最少的 API

最小的 API 依賴於許多擴充套件方法來序列化到/從 JSON。它們允許JsonSerializerOptions提供,但否則會退回到JsonOptionsHttContext.Request.Services. 您可以在啟動時配置這些選項:

builder.Services.Configure<JsonOptions>(opt =>{    opt.SerializerOptions.PropertyNamingPolicy = new SnakeCaseNamingPolicy());});

注意,你需要配置的Microsoft.AspNetCore.Http.Json.JsonOptions不是Mvc名稱空間下的類。

我在深入研究原始碼時發現的一件事是,序列化物件ObjectResultIResult實現的基類僅支援序列化 JSON。有人告訴我這是設計使然,因為大多數開發人員很少需要支援其他媒體型別。如果您需要支援內容協商,您可能需要構建自己的IResult.

授權

我想介紹的最後一個功能是授權。身份驗證和授權都作為中介軟體存在,可用於任何風格的 ASP.NET Core 應用程式。新增 MVC 或 Minimal API 中介軟體之前,您需要確保在應用程式中同時註冊授權服務和中介軟體:

var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services    .AddAuthentication(JwtBearerDefaults.AuthenticationScheme)    .AddJwtBearer();builder.Services.AddAuthorization();builder.Services.AddControllers(); // If MVCvar app = builder.Build();// Configure the HTTP request pipeline.if (builder.Environment.IsDevelopment()){    app.UseDeveloperExceptionPage();}app.UseAuthentication();app.UseAuthorization(); // <-- this needs to come firstapp.MapControllers(); // MVCapp.MapGet("/", () => "Hello World!"); // Minimal APIsapp.Run();

上面的例子是使用 JWT Bearer 認證。

MVC 和 Minimal API 之間的主要區別在於您宣告授權要求的方式。

預設安全

如果您對所有端點都有相同的授權要求,我建議您將回退策略設定為要求經過身份驗證的使用者:

builder.Services.AddAuthorization(options =>{    options.FallbackPolicy = new AuthorizationPolicyBuilder()      .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)      .RequireAuthenticatedUser();})

如果您有其他要求或需要允許對特定端點進行匿名訪問,您可以使用以下說明註釋您的端點。

MVC

在 MVC 應用程式中,使用[Authorize]屬性裝飾您的控制器和/或操作以指定您的授權要求。此屬性允許您指定角色和策略。此示例取自Microsoft Docs,將AtLeast21策略應用於控制器中定義的所有操作:

[Authorize(Policy = "AtLeast21")]public class AlcoholPurchaseController : Controller{    public IActionResult Index() => Ok();}

如果您的某些 API 端點需要允許匿名訪問,您可以使用以下[AllowAnonymous]屬性裝飾這些操作:

[AllowAnonymous][HttpGet("/free-for-all")]public IActionResult FreeForAll(){    return Ok();}

最少的API

為了使用 Minimal API 實現相同的行為,我們可以將額外的後設資料附加到端點,如下所示:

app.MapGet("/alcohol", () => Results.Ok())    .RequireAuthorization("AtLeast21");

同樣,要允許匿名訪問:

app.MapGet("/free-for-all", () => Results.Ok())    .AllowAnonymous();

後來我發現[Authorize]在使用方法組定義處理程式時可以使用與 MVC相同的屬性:

[Authorize("AtLeast21")]string Alcohol(){    }

包起來

最小 API 提供了一種使用 ASP.NET Core 構建 API 的替代方法。儘管很容易將它們視為“程式碼較少的 API”,但主要的好處是您擁有一個輕量級的基礎,您可以在此基礎上挑選所需的元件,而不是像 MVC 那樣沉重的東西,後者可能包含許多出色的功能你不使用(例如過濾器)。在許多情況下,這可能會導致服務佔用空間小得多,並隨後獲得效能提升。

值得一提的是,過去曾有社群努力實現同樣的目標。Nancy在 Web API / OWIN 時代為我們提供了類似的東西,最近Carter為 ASP.NET Core 出現,提供與 Minimal API 類似的功能。

作為 ASP.NET Core 開發人員,您現在在如何構建 API 方面有多種選擇,這隻能是一件好事。如果您希望本文涵蓋任何其他功能,請在Twitter 上聯絡

相關文章