jk's notes
  • Minimal API 中是 WebApplication 和 WebApplicationBuilder

Minimal API 中是 WebApplication 和 WebApplicationBuilder

文档地址

主要介绍 WebApplication 和 WebApplicationBuilder 的使用.

这两个用于创建 ASP.NET Core 的主机 (我是这么理解的).

所谓主机, 可以理解为程序运行的载体. 主机维护了:

  • 整个程序的声明周期.
  • 各个组件模块.
  • 各个中间件.
  • 依赖注入系统等.

可以简单将其看成一个运行平台, 类比于虚拟机软件中的虚拟机, 嵌入式开发中的操作系统 (例如宙合的 LuatOS, 鸿蒙等).

使用模板生成代码 (.NET8)

dotnet new web

然后生成:

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

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

app.Run();

其中

  • WebAPplication.CreateBuilder() 返回的便是 WebApplicationBuiler 对象.
  • builder.Build() 返回的是 WebApplication 对象.

从使用的角度看:

  • WebApplicationBuilder 用于配置主机, 例如中间件, 服务等.
  • WebApplication 即为主机, 用于配置运行时使用的管道服务等, 并用于启动服务.

WebApplication

创建方式:

  • 利用 WebApplicationBuilder 的 Build 方法来获得.
  • 直接使用 WebApplication.Create() 来创建.

下面列举使用 它 可以用来处理什么.

使用端口

端口配置可以使用:

  • 编辑 Properties/launchSettings.json 文件中的配置
  • 给 app.Run() 方法传参. 例如 app.Run("http://localhost:3000");
  • 向 app.Urls 中添加 url. 例如: app.Urls.Add("http://localhost:3000");. 这样可以配置多端口.
  • 使用命令行传参. 例如: dotnet run --urls="https://localhost:7777"
  • 使用环境变量
    • 推荐使用 ASPNETCORE_URLS 环境变量. 该环境变量也支持多端口.
    • 也可以直接使用 var port = Environment.GetEnvironmentVariable("PORT") ?? "3000"; 这类语法.
  • 监听所有接口:
    • http://*:3000
    • http://+:3000
    • http://0.0.0.0:3000
    • 使用 ASPNETCORE_HTTPS_PORTS 环境变量. 例如: ASPNETCORE_HTTP_PORTS=3000;5005 和 ASPNETCORE_HTTPS_PORTS=5000.

优先级是一个问题

使用指定开发证书的 HTTPS

在 appsettings.json 中配置证书

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Kestrel": {
    "Certificates": {
      "Default": {
        "Path": "cert.pem",
        "KeyPath": "key.pem"
      }
    }
  }
}

通过配置指定证书 (逻辑与 appsettings.json 是一样的).

// Configure the cert and the key
builder.Configuration["Kestrel:Certificates:Default:Path"] = "cert.pem";
builder.Configuration["Kestrel:Certificates:Default:KeyPath"] = "key.pem";

使用证书 API

builder.WebHost.ConfigureKestrel(options =>
{
    options.ConfigureHttpsDefaults(httpsOptions =>
    {
        var certPath = Path.Combine(builder.Environment.ContentRootPath, "cert.pem");
        var keyPath = Path.Combine(builder.Environment.ContentRootPath, "key.pem");

        httpsOptions.ServerCertificate = X509Certificate2.CreateFromPemFile(certPath, 
                                         keyPath);
    });
});

读取环境

使用 app.Environment 来引用环境.

细节参考文档环境.

读取配置

使用 app.Configuration 来引用配置文件. 例如:

var message = app.Configuration["HelloKey"] ?? "Config failed!";

它会读取 appsettings.json 中的 "HelloKey" 键.

细节可以参考文档.

调用日志接口

例如: app.Logger.LogInformation("The app started");

细节可以参考文档.

访问依赖注入容器

这个功能比较有用, 在代码中用于直接访问服务.

using (var scope = app.Services.CreateScope()) {
    var sampleService = scope.ServiceProvider.GetRequiredService<SampleService>();
    sampleService.DoSomething();
}

细节可以参考文档.

添加中间件

// Setup the file server to serve static files.
app.UseFileServer();

细节可以参考文档.

WebApplicationBuilder

可以直接创建 WebApplication, 但是如果需要细节控制 (配置各种服务等), 就需要先创建 WebAPplicationBuilder, 利用它来进行配置, 然后在基于配置好的 WebApplictionBuilder 来创建 WebApplication.

更改内容根, 应用程序名称和环境

直接创建时通过代码修改

var builder = WebApplication.CreateBuilder(new WebApplicationOptions {
    Args = args,
    ApplicationName = typeof(Program).Assembly.FullName,
    ContentRootPath = Directory.GetCurrentDirectory(),
    EnvironmentName = Environments.Staging,
    WebRootPath = "customwwwroot"
});

Console.WriteLine($"Application Name: {builder.Environment.ApplicationName}");
Console.WriteLine($"Environment Name: {builder.Environment.EnvironmentName}");
Console.WriteLine($"ContentRoot Path: {builder.Environment.ContentRootPath}");
Console.WriteLine($"WebRootPath: {builder.Environment.WebRootPath}");

var app = builder.Build();

使用环境变量或命令行修改

修改目标使用的环境变量对应的命令行参数
应用程序名称ASPNETCORE_APPLICATIONNAME--applicationName
环境名称ASPNETCORE_ENVIRONMENT--environment
内容根ASPNETCIRE_CONTENTROOT--contentRoot

添加配置提供程序

builder.Configuration.AddIniFile("appsettings.ini");

细节可以参考文档: 文件配置提供程序.

读取配置

默认可以从多个位置读取配置:

  • appSettings.json, appSettings.{environment}.json
  • 环境变量
  • 命令行

细节可以参考文档: 默认配置.

var message = builder.Configuration["HelloKey"] ?? "Hello";

添加日志提供程序

// Configure JSON logging to the console.
builder.Logging.AddJsonConsole();

添加服务

// Add the memory cache services.
builder.Services.AddMemoryCache();

// Add a custom scoped service.
builder.Services.AddScoped<ITodoRepository, TodoRepository>();

自定义 IHostBuilder

利用 Host 属性来访问 IHostBuilder:

// Wait 30 seconds for graceful shutdown.
builder.Host.ConfigureHostOptions(o => o.ShutdownTimeout = TimeSpan.FromSeconds(30));

自定义 WebHostBuilder

利用 WebHost 属性来访问 IWebHostBuilder:

// Change the HTTP server implemenation to be HTTP.sys based
builder.WebHost.UseHttpSys();

修改 Web 根

默认情况下, Web 根相对于 wwwroot 文件夹路径的. Web 根是静态文件中间件查找静态文件的位置.

可以使用 WebHostOptions, 命令行, 或 UseWebRoot 方法来修改:

var builder = WebApplication.CreateBuilder(new WebApplicationOptions {
    Args = args,
    // Look for static files in webroot
    WebRootPath = "webroot"
});

自定义依赖注入容器 (DI 容器)

下面示例使用 Autofac:

var builder = WebApplication.CreateBuilder(args);

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());

// Register services directly with Autofac here. Don't
// call builder.Populate(), that happens in AutofacServiceProviderFactory.
builder
  .Host
  .ConfigureContainer<ContainerBuilder>(builder => {
    builder.RegisterModule(new MyApplicationModule())
  });

var app = builder.Build();

开发人员异常页

开发人员异常页是默认配置的, 如下, 访问 / 可以看到一个友好的异常页面:

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

app.MapGet("/", () => {
    throw new InvalidOperationException("Oops, the '/' route has thrown an exception.");
});

app.Run();
Last Updated:
Contributors: jk