跳到主要内容

csharp的最小api

C# 在 dotnet6 之后添加了 minimalapi, 这允许开发者只需使用少量代码即可构建出一个可用的api程序

创建项目

可在命令行中执行以下代码创建项目

dotnet new webapi -minimal -n myapp

根据使用的sdk版本, 创建的项目模板可能会有所不同, 比如我在用的sdk版本是8.0.111, 模板中program.cs的内容如下:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

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

app.UseHttpsRedirection();

var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};

app.MapGet("/weatherforecast", () =>
{
var forecast = Enumerable.Range(1, 5).Select(index =>
new WeatherForecast
(
DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
))
.ToArray();
return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi();

app.Run();

record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}

上面创建了一个返回列表的接口, 不过这些代码对于讲解来说还是有点多余, 可将 Program.cs 里面的内容都删掉, 从头开始写起

创建接口

var app = WebApplication.CreateBuilder(args).Build();
app.MapGet("/", () => "Hello, World!");
app.Run();

其实只需要三行即可在启动端口的根目录下直接创建一个api接口, 启动程序后访问对应站点即可看到浏览器上输出的 Hello, World!

在miniapi中可以非常简单地创建 restful api

  • app.MapPost
  • app.MapDelete
  • app.MapPut
  • app.MapGet

通过以上的四个方法可以完成增删改查四种基本的restful操作

参数匹配

由于miniapi接收的是委托类型的参数, 所以在定义参数时与之前常用的controller不同

app.MapGet(route, ([FromQuery] string data) => data);

[FromQuery] 可以说是最基础的一种参数接收形式, 用于接收请求路径?之后的参数内容, 例如http://{host}:{port}/getdata?data=123, 委托中获取到的data就会是123

不过有一点需要注意, 之前在 controller 中可以指定自定义类型来接受多个参数, 比如[FromQuery]InputData data这种的, 可以一次性接收多个参数, 但是在 miniapi 中不能直接这么使用, InputData必须要有将 string 类型的参数字符串转换为 InputDataTryPrase 方法, 这样就显得尤为麻烦

因此如果想要通过 [FromQuery] 接收多个参数, 最好还是将参数拆开定义

app.MapGet(route, ([FromQuery] string data, [FromQuery] int num) => $@"{data}:{num}");

不过挺好的是 [FromBody] 的用法和以前没啥区别, 还是一样的非常方便

app.MapPost(route, ([FromBody] InputData data) => $@"{data.Data}:{data.Num}");
public class InputData
{
public string Data { get; set; }
public string Num { get; set; }
}

使用依赖注入

众所周知在现在的dotnet中, 依赖注入(DI)是必不可少的, 虽然 miniapi 很简单, 但还是可以正常用上的

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton(new Config { Data = "233" });
...
app.MapPost(route, ([FromServices] Config config) => config.Data);
app.Run();
public class Config
{
public string Data { get; set; }
}

在委托的参数列表里可以使用 [FromServices] 从依赖注入容器中获取注册过的实例

提示

其实在 controller 中也可以使用这种方式注入实例, 只不过在正常情况下一般还是用构造函数注入, 但 miniapi 中只能用这种方式

这种注入方式讲究的就是用啥注入啥, 但是在业务复杂并且需要注入的实例数量比较多的时候, 委托的参数列表就会显得太过冗长, 如果接口数量也同时上升, 那么重复注入的情况就会出现很多次, 这种情况下可能就不如 controller 方便了

总结

miniapi 虽然能满足一些简单的需求, 但对于复杂的业务, 还是建议使用 controller 来实现