.NET 6.0 Minimal API 介绍

前言

Minimal API是.NET 6中新增的模板,借助C# 10的一些特性以最少的代码运行一个Web服务。本文脱离VS通过VS Code,完成一个简单的Minimal Api项目的开发

创建项目

随便新建一个文件夹,用来管理我们的项目文件,文件夹内启动命令行,通过dotnet new web创建项目。.

.NET 6.0 Minimal API 介绍

还是一堆文件, 什么时候一个Program.cs文件就能跑起一个Web项目没准哪天也可以了

运行项目

项目目录下执行dotnet run,运行项目。

.NET 6.0 Minimal API 介绍

尝试玩点花的用网页版VS Code (https://vscode.dev/)运行项目,不过并没有我想象中那么强,还不支持。
.NET 6.0 Minimal API 介绍

Coding

builder实例提供了Services属性,可以完成原本Startup类ConfigureServices方法中注册服务的工作,Configure方法的一些Use操作则通过app来完成。

builder.Services.AddMemoryCache();
//todo
app.UseStaticFiles();
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", $"{builder.Environment.ApplicationName} v1"));
}

MapGet变种

通过Build出来的app实例的MapGet方法实现路由的映射。

app.MapGet("/", () => "Hello World!");
//app.Map("/",[HttpGet] () => "Hello World!");
//app.MapMethods("/", new List<string>() { HttpMethod.Get.ToString() }, () => "Hello World!");

可以看到通过Delegate的方式可以直接在Delegate前加上对应的特性。async关键字同样可以直接标记在Delegate前。

路由映射感觉还差点意思。不能像其它语言框架一样进行不同版本的管理,如:

var api = app.Part("v1",middleware);
api.MapGet("", () =>{ return ""; });

Application

代码内直接修改应用程序配置,如修改监听端口

app.Urls.Add("http://localhost:3000");
//app.Urls.Add("http://localhost:4000");
//app.Run();
app.Run("http://localhost:4000");

优先级 app.Run > app.Urls.Add > launchSettings

Dependency Injection

Minimal API中无法使用构造函数注入,可以通过参数方式注入,可以忽略掉FromServices特性的标记。

.NET 6.0 Minimal API 介绍

Context

一些Http请求的上下文信息也可以通过参数直接指定,方法体内直接使用,代替MVC中的Request等。如:

  • HttpContext
  • HttpRequest
  • HttpResponse
  • ClaimsPrincipal
  • CancellationToken
app.MapGet("/context", (HttpContext httpContext) => new 
{
    Data = httpContext.Connection.Id
});

更多类型参考:github

Responses

通过静态类Results返回标准的相应类型,实现和ControllerBase提供对应方法相同的效果。

app.MapGet("/ok/{id}", (int id) =>
{
    return Results.Ok($"ok:{id}");
});

Link Generation

通过扩展方法WithXXX等可以对路由进行一些配置,如通过WithName指定名称,再通过LinkGenerator生产对应Uri,避免硬编码

app.MapGet("/context", (HttpContext httpContext) => new
{
    Data = httpContext.Connection.Id
}).WithName("hi");
app.MapGet("hello", (LinkGenerator linker) =>
        $"The link to the hello route is {linker.GetPathByName("hi", values: null)}");

除了WithXXX等一些列RoutingEndpointConvention扩展方法外,还提供了AuthorizationEndpointConvention相关扩展方法RequireAuthorization、AllowAnonymous代替MVC模式中的相关特性(特性也还可以用只是多了一个支持方式)。

本文只列出Minimal API的一些简单用法,集成Swagger等用法内容参考:https://minimal-apis.github.io/hello-minimal/

接口的返回状态码和类型等可以通过扩展方法Produces说明,如:Produces(contentType:"application/xml"); ,但是接口备注貌似还不支持,我尝试了很多方式都不能正确显示。

Code Format

Minimal API上面示例存在的问题是Program文件中会有太多的编码,所有路由的映射和响应都在一起,虽然可以通过如下方式使用静态方法抽离响应方法,但所有的Route Map还是列在一起,不能像Controller一下分离。

var handler = new HelloHandler();

app.MapGet("/", handler.Hello);

class HelloHandler
{
    public string Hello() 
    {
        return "Hello World";
    }
}

可以借助开源框架MASA.Contrib提供的MASA.Contrib.Service.MinimalAPIs完成代码封装。

详细用法参考MASA.EShop

.NET 6.0 Minimal API 介绍