前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >一题多解,ASP.NET Core应用启动初始化的N种方案[下篇]

一题多解,ASP.NET Core应用启动初始化的N种方案[下篇]

作者头像
蒋金楠
发布于 2022-09-08 07:12:49
发布于 2022-09-08 07:12:49
75200
代码可运行
举报
文章被收录于专栏:大内老A大内老A
运行总次数:0
代码可运行

[接上篇]“天下大势,分久必合,合久必分”,ASP.NET应用通过GenericWebHostService这个承载服务被整合到基于IHostBuilder/IHost的服务承载系统中之后,也许微软还是意识到Web应用和后台服务的承载方式还是应该加以区分,于是推出了基于WebApplicationBuilder/WebApplication的承载方式。我们可以将其称为第三代承载模式,它有一个官方的名称叫做“Minimal API”。Minimal API同样面临向后兼容的问题,而且这次需要同时兼容前面两代承载模式,所以我们会发现“上篇”中提到的一系列初始化操作有了更多实现方式。[本文部分内容来源于《ASP.NET Core 6框架揭秘》第15章]

目录 一、Minimal API 二、推荐编程方式 三、承载环境 四、承载配置 五、应用配置 六、服务注册 七、中间件注册 八、Startup类型不再被支持

一、Minimal API

基于Minimal API的第三代应用承载方式的推出并非又回到了起点,因为底层的承载方式其实没有改变,它只是在上面再封装了一层而已。新的应用承载方式依然采用“构建者(Builder)”模式,核心的两个对象分别为WebApplication和WebApplicationBuilder,代表承载应用的WebApplication对象由WebApplicationBuilder对象进行构建。第二代承载模式需要提供针对IWebHostBuilder接口的兼容,作为第三代承载模式的Minimal API则需要同时提供针对IWebHostBuilder和IHostBuilder接口的兼容,此兼容性是通过这两个接口的实现类型ConfigureWebHostBuilder和ConfigureHostBuilder达成的。

WebApplicationBuilder类型的WebHost和Host属性返回了这两个对象,之前定义在IWebHostBuilder和IHostBuilder接口上的绝大部分API(并非所有API)借助它们得以复用。也正是有了这段历史,我们会发现相同的功能具有两到三种不同的编程方式。比如IWebHostBuilder和IHostBuilder接口上都提供了注册服务的方法,而WebApplicationBuilder类型利用Services属性直接将存放服务注册的IServiceCollection对象暴露出来,所以任何的服务注册都可以利用这个属性来完成。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public sealed class WebApplicationBuilder
{
    public ConfigureWebHostBuilder WebHost { get; }
    public ConfigureHostBuilder Host { get; }

    public IServiceCollection Services { get; }
    public ConfigurationManager Configuration { get; }
    public ILoggingBuilder Logging { get; }

    public IWebHostEnvironment Environment { get; }

    public WebApplication Build();
}

public sealed class ConfigureWebHostBuilder : IWebHostBuilder, ISupportsStartup
public sealed class ConfigureHostBuilder : IHostBuilder, ISupportsConfigureWebHost

IWebHostBuilder和IHostBuilder接口都提供了设置配置和日志的方法,这两方面的设置都可以利用WebApplicationBuilder利用Configuration和Logging暴露出来的ConfigurationManager和ILoggingBuilder对象来实现。既然我们采用了Minimal API,那么我们就应该尽可能得使用WebApplicationBuilder类型提供的API。

二、推荐编程方式

我们再次使用[上篇]提供的实例来演示承载配置、应用配置、承载环境、服务注册和中间件在Minimal API下的标准编程方式。该演示实例会注册如下这个FoobarMiddleware中间件,后者利用注入的IHandler服务完成请求的处理工作。作为IHandler接口的默认实现类型,Handler利用构造函数注入的IOptions<FoobarbazOptions>对象得到配置选项FoobarbazOptions,并将其内容作为请求的响应。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class FoobarMiddleware
{
    private readonly RequestDelegate _next;
    public FoobarMiddleware(RequestDelegate _) { }
    public Task InvokeAsync(HttpContext httpContext, IHandler handler) => handler.InvokeAsync(httpContext);
}

public interface IHandler
{
    Task InvokeAsync(HttpContext httpContext);
}

public class Handler : IHandler
{
    private readonly FoobarbazOptions _options;
    private readonly IWebHostEnvironment _environment;

    public Handler(IOptions<FoobarbazOptions> optionsAccessor, IWebHostEnvironment environment)
    {
        _options = optionsAccessor.Value;
        _environment = environment;
    }

    public Task InvokeAsync(HttpContext httpContext)
    {
        var payload = @$"
Environment.ApplicationName: {_environment.ApplicationName}
Environment.EnvironmentName: {_environment.EnvironmentName}
Environment.ContentRootPath: {_environment.ContentRootPath}
Environment.WebRootPath: {_environment.WebRootPath}
Foo: {_options.Foo}
Bar: {_options.Bar}
Baz: {_options.Baz}
";
        return httpContext.Response.WriteAsync(payload);
    }
}

public class FoobarbazOptions
{
    public string Foo { get; set; } = default!;
    public string Bar { get; set; } = default!;
    public string Baz { get; set; } = default!;
}

我们会利用与当前“承载环境”对应配置来绑定配置选项FoobarbazOptions,后者的三个属性分别来源于三个独立的配置文件。其中settings.json被所有环境共享,settings.dev.json针对名为“dev”的开发环境。我们为承载环境提供更高的要求,在环境基础上进步划分子环境,settings.dev.dev1.json针对的就是dev下的子环境dev1。针对子环境的设置需要利用上述的承载配置来提供。

如下所示的就是上述三个配置文件的内容。如果当前环境和子环境分别为dev和dev1,那么配置选项FoobarbazOptions的内容将来源于这三个配置文件。细心的朋友可能还注意到了:我们并没有放在默认的根目录下,而是放在创建的resources目录下,这是因为我们需要利用针对承载环境的设置改变ASP.NET Core应用存放内容文件和Web资源文件的根目录。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
settings.json
{
  "Foo": "123"
}

settings.dev.json
{
  "Bar": "abc"
}

settings.dev.dev1.json
{
  "Baz": "xyz"
}

如下所示的代码体现了承载配置、应用配置、承载环境、服务注册和中间件注册这五种初始化操作在Minimal API中的标准编程方式。与承载环境相关的承载配置(环境名称和内容文件与Web资源文件根目录)被定义在WebApplicationOptions配置选项上,并将其作为参数调用WebApplication的静态工厂方法CreateBuilder将WebApplicationBuilder对象构建出来。WebApplicationBuilder的Configuration属性返回一个ConfigurationManager对象,由于它同时实现了IConfigurationBuilder和IConfiguration接口,所以我们利用利用它来设置配置源,并且能够确保配置原提供的配置能够实时反映到这个对象上。从编程的角度来说,Minimal API不再刻意地区分承载配置和应用配置,因为针对它们的设置都由这个ConfigurationManager对象来完成。我们利用这个对象将表示“子环境名称”的承载配置进行了设置。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
using App;
var options = new WebApplicationOptions
{
    Args = args,
    EnvironmentName = "dev",
    ContentRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources"),
    WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources", "web")
};
var appBuilder = WebApplication.CreateBuilder(options);
appBuilder.Configuration["SubEnvironment"] = "dev1";
appBuilder.Configuration
    .AddJsonFile(path: "settings.json", optional: false)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.json", optional: true)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.{appBuilder.Configuration["SubEnvironment"]}.json", optional: true);
appBuilder.Services
    .AddSingleton<IHandler, Handler>()
    .Configure<FoobarbazOptions>(appBuilder.Configuration);
var app = appBuilder.Build();
app.UseMiddleware<FoobarMiddleware>();
app.Run();

在完成了针对承载配置(含承载环境)的设置后,我们利用同一个ConfigurationManager对象完成针对应用配置的设置。具体来说,我们针对当前环境注册了三个对应的配置文件,定位配置文件的环境名称来源于WebApplicationBuilder的Environment属性返回的IWebHostEnvironment对象,而子环境则直接从ConfigurationManager对象中提取。

WebApplicationBuilder的Services属性返回用来存放服务注册的IServiceCollection对象,所以需要的服务注册直接添加到这个集合中就可以了。由于WebApplicationBuilder自身能够提供承载环境和配置,所以针对环境以及当前配置进行针对性的服务注册变得更加直接。我们利用这个IServiceCollection对象完成了针对IHandler/Handler的注册,以及将配置绑定到FoobarbazOptions配置选项上。

在此之后,我们调用WebApplicationBuilder的Build方法将代表Web应用的WebApplication对象构建出来。由于后者的类型实现了IApplicationBuilder接口,所以我们可以直接利用它来完成中间件的注册,我们自定义的FoobarMiddleware中间件就可以调用它的UseMiddleware<TMiddleware>方法进行注册的。程序启动之后,利用浏览器的请求会得到如下图所示的结果。

三、承载环境

承载环境(环境名称、内容文件根目录和Web资源文件根目录)相关的承载配置在Minimal API只支持如下三种设置方式:

  • 利用WebApplicationOptions(如我们提供的演示程序)
  • 利用命令行参数
  • 利用环境变量

我们按照如下的方式对演示程序进行了改写,摒弃了WebApplicationOptions配置选项,改用三个对应的环境变量。由于环境变量会默认作为配置源,所以自然也可以利用环境变量设置子环境名称。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Environment.SetEnvironmentVariable("ASPNETCORE_ENVIRONMENT", "dev");
Environment.SetEnvironmentVariable("ASPNETCORE_SUBENVIRONMENT", "dev1");
Environment.SetEnvironmentVariable("ASPNETCORE_CONTENTROOT", Path.Combine(Directory.GetCurrentDirectory(), "resources"));
Environment.SetEnvironmentVariable("ASPNETCORE_WEBROOT", Path.Combine(Directory.GetCurrentDirectory(), "resources", "web"));

var appBuilder = WebApplication.CreateBuilder(args);

appBuilder.Configuration
    .AddJsonFile(path: "settings.json", optional: false)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.json", optional: true)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.{appBuilder.Configuration["SubEnvironment"]}.json", optional: true);
appBuilder.Services
    .AddSingleton<IHandler, Handler>()
    .Configure<FoobarbazOptions>(appBuilder.Configuration);
var app = appBuilder.Build();
app.UseMiddleware<FoobarMiddleware>();
app.Run();

由于WebApplicationBuilder利用WebHost属性提供的ConfigureWebHostBuilder(实现了IWebHostBuilder接口)对象来兼容原来定义在IWebHostBuilder接口上的API,有的人可以会觉得我们一定也能够像之前那样利用这个对象来设置承载环境,我们不妨来试试是否可行。如下面的代码片段所示,我们直接调用该对象的UseEnvironment、UseContentRoot和UseWebRoot方法对环境名称和内容文件与Web资源文件根目录进行了设置。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var appBuilder = WebApplication.CreateBuilder(args);
appBuilder.WebHost
    .UseEnvironment("dev")
    .UseContentRoot(Path.Combine(Directory.GetCurrentDirectory(), "resources"))
    .UseWebRoot(Path.Combine(Directory.GetCurrentDirectory(), "resources", "web"));

appBuilder.Configuration["SubEnvironment"] = "dev1";
appBuilder.Configuration
    .AddJsonFile(path: "settings.json", optional: false)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.json", optional: true)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.{appBuilder.Configuration["SubEnvironment"]}.json", optional: true);
appBuilder.Services
    .AddSingleton<IHandler, Handler>()
    .Configure<FoobarbazOptions>(appBuilder.Configuration);
var app = appBuilder.Build();
app.UseMiddleware<FoobarMiddleware>();
app.Run();

不幸的是,当我们启动程序之后会抛出如下所示的异常,并提示环境名称不能更改(其他承载环境属性也是一样),推荐使用WebApplicationOptions配置选项。由于承载环境是承载配置的范畴,但是Minimal API并没有刻意将两者区分开来,因为所有配置都实时体现在WebApplicationBuilder的Configuration属性返回的ConfigurationManager对象上。承载环境需要在最开始就被确定下来,因为后续后续配置的设置和服务注册都依赖于它,所以WebApplicationBuilder对象一旦被创建,承载环境就会固定下来,不能在改变。

可能有人还不死心,想到WebApplicationBuilder的Host属性不是还提供了一个ConfigureHostBuilder(实现了IHostBuilder接口)对象吗?我们是否可以按照如下的方式利用这个对象来设置承载环境相呢。很遗憾,我们同样会得到上面这个错误。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var appBuilder = WebApplication.CreateBuilder(args);
appBuilder.Host
    .UseEnvironment("dev")
    .UseContentRoot(Path.Combine(Directory.GetCurrentDirectory(), "resources"));
appBuilder.WebHost
    .UseWebRoot(Path.Combine(Directory.GetCurrentDirectory(), "resources", "web"));

appBuilder.Configuration["SubEnvironment"] = "dev1";
appBuilder.Configuration
    .AddJsonFile(path: "settings.json", optional: false)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.json", optional: true)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.{appBuilder.Configuration["SubEnvironment"]}.json", optional: true);
appBuilder.Services
    .AddSingleton<IHandler, Handler>()
    .Configure<FoobarbazOptions>(appBuilder.Configuration);
var app = appBuilder.Build();
app.UseMiddleware<FoobarMiddleware>();
app.Run();

不论是IWebHostBuilder的UseEnvironment、UseContentRoot和UseWebRoot方法,还是IHostBuilder的UseEnvironment和UseContentRoot方法,它们最终都是对配置系统的更新,那么我们是否可以利用WebApplicationBuiler提供的ConfigurationManager对象按照如下的方式直接修改与承载环境相关的配置呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var appBuilder = WebApplication.CreateBuilder(args);

appBuilder.Configuration["Environment"] = "dev";
appBuilder.Configuration["SubEnvironment"] = "dev1";
appBuilder.Configuration["ContentRoot"] = Path.Combine(Directory.GetCurrentDirectory(), "resources");
appBuilder.Configuration["WebRoot"] = Path.Combine(Directory.GetCurrentDirectory(), "resources","web");
var app = appBuilder.Build();
app.MapGet("/", (IWebHostEnvironment environment) => Results.Json(environment, new JsonSerializerOptions {  WriteIndented = true}));
app.Run();

在配置了与承载环境相关的几个属性之后,我们注册了一个针对根路径的路由,路由注册里会直接以JSON的形式返回当前承载环境。程序运行之后,针对根路径的请求会得到如下所示的输出结果,可以看出利用配置对承载环境的设置并没有生效。

四、承载配置

承载配置会影响应用配置,比如针对演示实例的应用配置在设置的时候需要使用到对当前“子环境名称”的设置。承载环境还会影响服务注册,我们针对设置的“子环境”进行针对性的服务注册也是一个常见的需求。由于Minimal API将这两种类型的配置都集中到WebApplicationBuilder提供的ConfigurationManager对象上,所以针对承载配置的设置应该放在服务注册和设置应用配置之前。

由于WebApplicationBuilder可以为我们提供IWebHostBuilder和IHostBuilder,所以只要不涉及承载环境相关的几个预定义配置,其他承载配置(比如演示实例涉及的子环境名称)完全可以利用这两个对象进行设置。下面的代码片段演示了通过调用IWebHostBuilder的UseSettings方法来设置子环境名称。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var options = new WebApplicationOptions
{
    Args = args,
    EnvironmentName = "dev",
    ContentRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources"),
    WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources", "web")
};
var appBuilder = WebApplication.CreateBuilder(options);
appBuilder.WebHost.UseSetting("SubEnvironment", "dev1");
appBuilder.Configuration
    .AddJsonFile(path: "settings.json", optional: false)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.json", optional: true)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.{appBuilder.Configuration["SubEnvironment"]}.json", optional: true);
appBuilder.Services
    .AddSingleton<IHandler, Handler>()
    .Configure<FoobarbazOptions>(appBuilder.Configuration);
var app = appBuilder.Build();
app.UseMiddleware<FoobarMiddleware>();
app.Run();

子环境名称同样可以按照如下的方式利用IHostBuilder的ConfigureHostConfiguration方法进行设置。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var options = new WebApplicationOptions
{
    Args = args,
    EnvironmentName = "dev",
    ContentRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources"),
    WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources", "web")
};
var appBuilder = WebApplication.CreateBuilder(options);
appBuilder.Host.ConfigureHostConfiguration(config => config.AddInMemoryCollection(
    new Dictionary<string, string> { { "SubEnvironment" ,"dev1" } }));
appBuilder.Configuration
    .AddJsonFile(path: "settings.json", optional: false)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.json", optional: true)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.{appBuilder.Configuration["SubEnvironment"]}.json", optional: true);
appBuilder.Services
    .AddSingleton<IHandler, Handler>()
    .Configure<FoobarbazOptions>(appBuilder.Configuration);
var app = appBuilder.Build();
app.UseMiddleware<FoobarMiddleware>();
app.Run();

五、应用配置

Minimal API下针对应用配置的设置,最简单的方式莫过于上面演示的直接使用WebApplicationBuilder提供的ConfigurationManager对象。但是IWebHostBuilder和IHostBuilder接口的ConfigureAppConfiguration方法依然是可以使用的,所以演示实例针对应用配置的设置可以改写成如下两种形式。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var options = new WebApplicationOptions
{
    Args = args,
    EnvironmentName = "dev",
    ContentRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources"),
    WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources", "web")
};
var appBuilder = WebApplication.CreateBuilder(options);
appBuilder.Host.ConfigureHostConfiguration(config => config.AddInMemoryCollection(
    new Dictionary<string, string> { { "SubEnvironment" ,"dev1" } }));
appBuilder.WebHost.ConfigureAppConfiguration((context, config) => config
    .AddJsonFile(path: "settings.json", optional: false)
    .AddJsonFile(path: $"settings.{context.HostingEnvironment.EnvironmentName}.json", optional: true)
    .AddJsonFile(path: $"settings.{context.HostingEnvironment.EnvironmentName}.{context.Configuration["SubEnvironment"]}.json", optional: true));
appBuilder.Services
    .AddSingleton<IHandler, Handler>()
    .Configure<FoobarbazOptions>(appBuilder.Configuration);
var app = appBuilder.Build();
app.UseMiddleware<FoobarMiddleware>();
app.Run();
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var options = new WebApplicationOptions
{
    Args = args,
    EnvironmentName = "dev",
    ContentRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources"),
    WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources", "web")
};
var appBuilder = WebApplication.CreateBuilder(options);
appBuilder.Host.ConfigureHostConfiguration(config => config.AddInMemoryCollection(
    new Dictionary<string, string> { { "SubEnvironment" ,"dev1" } }));
appBuilder.Host.ConfigureAppConfiguration((context, config) => config
    .AddJsonFile(path: "settings.json", optional: false)
    .AddJsonFile(path: $"settings.{context.HostingEnvironment.EnvironmentName}.json", optional: true)
    .AddJsonFile(path: $"settings.{context.HostingEnvironment.EnvironmentName}.{context.Configuration["SubEnvironment"]}.json", optional: true));
appBuilder.Services
    .AddSingleton<IHandler, Handler>()
    .Configure<FoobarbazOptions>(appBuilder.Configuration);
var app = appBuilder.Build();
app.UseMiddleware<FoobarMiddleware>();
app.Run();

六、服务注册

既然WebApplicationBuilder的Services属性已经提供了用来存放服务注册的IServiceCollection对象,那么Minimal API下可以直接可以利用它来注册我们所需的服务。但是IWebHostBuilder和IHostBuilder接口的ConfigureServices方法依然是可以使用的,所以演示实例针对服务的注册可以改写成如下两种形式。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var options = new WebApplicationOptions
{
    Args = args,
    EnvironmentName = "dev",
    ContentRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources"),
    WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources", "web")
};
var appBuilder = WebApplication.CreateBuilder(options);
appBuilder.Configuration["SubEnvironment"] = "dev1";
appBuilder.Configuration
    .AddJsonFile(path: "settings.json", optional: false)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.json", optional: true)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.{appBuilder.Configuration["SubEnvironment"]}.json", optional: true);
appBuilder.WebHost.ConfigureServices((context, services) =>services
    .AddSingleton<IHandler, Handler>()
    .Configure<FoobarbazOptions>(context.Configuration));
var app = appBuilder.Build();
app.UseMiddleware<FoobarMiddleware>();
app.Run();
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var options = new WebApplicationOptions
{
    Args = args,
    EnvironmentName = "dev",
    ContentRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources"),
    WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources", "web")
};
var appBuilder = WebApplication.CreateBuilder(options);
appBuilder.Configuration["SubEnvironment"] = "dev1";
appBuilder.Configuration
    .AddJsonFile(path: "settings.json", optional: false)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.json", optional: true)
    .AddJsonFile(path: $"settings.{appBuilder.Environment.EnvironmentName}.{appBuilder.Configuration["SubEnvironment"]}.json", optional: true);
appBuilder.Host.ConfigureServices((context, services) =>services
    .AddSingleton<IHandler, Handler>()
    .Configure<FoobarbazOptions>(context.Configuration));
var app = appBuilder.Build();
app.UseMiddleware<FoobarMiddleware>();
app.Run();

七、中间件注册

中间件总是注册到IApplicationBuilder对象上,由于WebApplicationBuilder创建的WebApplication对象同时也是一个IApplicationBuilder对象,所以最简便快捷的中间件注册方法莫过于直接使用WebApplication对象。可能有人觉得也可以利用IWebHostBuiller的Configure方法来注册中间件,比如将我们的演示实例改写成如下的形式。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var options = new WebApplicationOptions
{
    Args = args,
    EnvironmentName = "dev",
    ContentRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources"),
    WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources", "web")
};
var appBuilder = WebApplication.CreateBuilder(options);
appBuilder.Host.ConfigureHostConfiguration(config => config.AddInMemoryCollection(
    new Dictionary<string, string> { { "SubEnvironment" ,"dev1" } }));
appBuilder.Host.ConfigureAppConfiguration((context, config) => config
    .AddJsonFile(path: "settings.json", optional: false)
    .AddJsonFile(path: $"settings.{context.HostingEnvironment.EnvironmentName}.json", optional: true)
    .AddJsonFile(path: $"settings.{context.HostingEnvironment.EnvironmentName}.{context.Configuration["SubEnvironment"]}.json", optional: true));
appBuilder.Services
    .AddSingleton<IHandler, Handler>()
    .Configure<FoobarbazOptions>(appBuilder.Configuration);
appBuilder.WebHost.Configure(app => app.UseMiddleware<FoobarMiddleware>());
var app = appBuilder.Build();
app.Run();

实际上是不可以的,启动改写后的程序会抛出如下的NotSupportedException异常,并提示定义在WebApplicationBuilder的WenHost返回的ConfugureWebHostBuilder对象的Configure方法不再被支持,中间件的注册只能利用WebApplication对象来完成。

八、Startup类型不再被支持

在Minimal API之前,将服务注册、中间件注册以及针对依赖注入容器的设置放在Startup类型中是一种被推荐的做法,但是这种编程方法在Minimal API中也不再被支持。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
var options = new WebApplicationOptions
{
    Args = args,
    EnvironmentName = "dev",
    ContentRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources"),
    WebRootPath = Path.Combine(Directory.GetCurrentDirectory(), "resources", "web")
};
var appBuilder = WebApplication.CreateBuilder(options);
appBuilder.Host.ConfigureHostConfiguration(config => config.AddInMemoryCollection(
    new Dictionary<string, string> { { "SubEnvironment" ,"dev1" } }));
appBuilder.Host.ConfigureAppConfiguration((context, config) => config
    .AddJsonFile(path: "settings.json", optional: false)
    .AddJsonFile(path: $"settings.{context.HostingEnvironment.EnvironmentName}.json", optional: true)
    .AddJsonFile(path: $"settings.{context.HostingEnvironment.EnvironmentName}.{context.Configuration["SubEnvironment"]}.json", optional: true));
appBuilder.WebHost.UseStartup<Startup>();
var app = appBuilder.Build();
app.Run();

public class Startup
{
    public Startup(IConfiguration configuration)=> Configuration = configuration;
    public IConfiguration Configuration { get; }
    public void ConfigureServices(IServiceCollection services)
    {
        services
             .AddSingleton<IHandler, Handler>()
            .Configure<FoobarbazOptions>(Configuration);
    }
    public void Configure(IApplicationBuilder app)=>app.UseMiddleware<FoobarMiddleware>();
}

上面的程序将服务注册和中间件注册放在按照约定定义的Startup类型中,在利用WebApplicationBuilder的WebHost属性得到提供的ConfigureWebHostBuilder对象之后,我们调用其UseStartup方法对这个Startup类型进行了注册。遗憾的是,应用启动时同样会得到如下所示类似的NotSupportedException异常。

一题多解,ASP.NET Core应用启动初始化的N种方案[上篇]

一题多解,ASP.NET Core应用启动初始化的N种方案[下篇]

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-07-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
一题多解,ASP.NET Core应用启动初始化的N种方案[上篇]
ASP.NET Core应用本质上就是一个由中间件构成的管道,承载系统将应用承载于一个托管进程中运行起来,其核心任务就是将这个管道构建起来。在ASP.NET Core的发展历史上先后出现了三种应用承载的编程方式,而且后一种编程模式都提供了针对之前编程模式的全部或者部分兼容,这就导致了一种现象:相同的更能具有N种实现方式。对这个发展历程不是特别了解的读者会有很多疑问?为什么这么多不同的编程模式都在作同一件事?它们之间的有什么差别之处?为什么有的API在最新的Minimal API又不能用了呢?[本文部分内容来源于《ASP.NET Core 6框架揭秘》第15章]
蒋金楠
2022/09/02
1.4K0
一题多解,ASP.NET Core应用启动初始化的N种方案[上篇]
ASP.NET Core 6框架揭秘实例演示[25]:配置与承载环境的应用
与服务注册一样,针对配置的设置同样可以采用三种不同的编程模式。第一种是利用WebApplicationBuilder的Host属性返回的IHostBuilder对象,它可以帮助我们设置面向宿主和应用的配置。IWebHostBuilder接口上面同样提供了一系列用来对配置进行设置的方法,我们可以将这些方法应用到WebApplicationBuilder的WebHost属性返回的IWebHostBuilder对象上。不过还是那句话,既然推荐使用Mininal API,最好还是采用最新的编程方式。(本篇提供的实例已经汇总到《ASP.NET Core 6框架揭秘-实例演示版》)
蒋金楠
2022/05/09
8420
ASP.NET Core 6框架揭秘实例演示[25]:配置与承载环境的应用
ASP.NET Core 6框架揭秘实例演示[27]:ASP.NET Core 6 Minimal API的模拟实现
Minimal API仅仅是在基于IHost/IHostBuilder的服务承载系统上作了小小的封装而已,它利用WebApplication和WebApplicationBuilder这两个类型提供了更加简洁的API,同时提供了与现有API的兼容。要成分理解Minimal API的实现原理,得先对服务承载系统有基本的理解,对此不了解的可以参阅《服务承载模型[上篇]》、《服务承载模型[下篇]》、《承载服务启动流程[上篇]》和《承载服务启动流程[下篇]》。对于本篇提供的模拟代码,可以从这里下载。
蒋金楠
2022/05/09
1.5K0
ASP.NET Core 6框架揭秘实例演示[27]:ASP.NET Core 6 Minimal API的模拟实现
ASP.NET Core应用基本编程模式[4]:基于承载环境的编程
基于IHostBuilder/IHost的承载系统通过IHostEnvironment接口表示承载环境,我们利用它不仅可以得到当前部署环境的名称,还可以获知当前应用的名称和存放内容文件的根目录路径。对于一个Web应用来说,我们需要更多的承载环境信息,额外的信息定义在IWebHostEnvironment接口中。[本文节选自《ASP.NET Core 3框架揭秘》第11章, 更多关于ASP.NET Core的文章请点这里]
蒋金楠
2020/11/24
7820
ASP.NET Core应用基本编程模式[4]:基于承载环境的编程
《ASP.NET Core 6框架揭秘》勘误
P5第2段 原文:由于创建的是一个针对 ASP.NET Core 的可执行控制台应用,所以将 OutputType 和 TargetFramework 的属性分别设置为“Exe”和“net6.0”。 改为:由于创建的是一个针对 .NET 6的可执行控制台应用,所以将 OutputType 和 TargetFramework 的属性分别设置为“Exe”和“net6.0”。 P7第2段 原文:由于创建的是 ASP.NET Core 的应用程序,所以最终生成的程序集被保存在“\bin\Debug\net6.0\
蒋金楠
2022/09/08
1.7K0
《ASP.NET Core 6框架揭秘》勘误
asp.net core 系列之Configuration
在ASP.NET Core中的App configuration 是通过configuration providers基于key-value对建立的。Configuration providers读取配置文件到key-value,从多种配置源中:
Vincent-yuan
2019/09/11
1.5K0
asp.net core 系列之Configuration
ASP.NET Core使用环境变量
通常在应用程序开发到正式上线,在这个过程中我们会分为多个阶段,通常会有 开发、测试、以及正式环境等。每个环境的参数配置我们会使用不同的参数,因此呢,在ASP.NET Core中就提供了相关的环境API,方便我们更好的去做这些事情。
HueiFeng
2020/02/21
2.1K0
[ASP.NET Core 3框架揭秘]服务承载系统[6]: 承载服务启动流程[下篇]
实际上HostBuilder对象并没有在实现的Build方法中调用构造函数来创建Host对象,该对象利用作为依赖注入容器的IServiceProvider对象创建的。为了可以采用依赖注入框架来提供构建的Host对象,HostBuilder必须完成前期的服务注册工作。总地来说,HostBuilder针对Host对象的构建大体可以划分为如下5个步骤:
蒋金楠
2020/03/19
1.5K0
ASP.NET Core 6框架揭秘实例演示[23]:ASP.NET Core应用承载方式的变迁
ASP.NET Core应用本质上就是一个由中间件构成的管道,承载系统将应用承载于一个托管进程中运行起来,其核心任务就是将这个管道构建起来。从设计模式的角度来讲,“管道”是构建者(Builder)模式最典型的应用场景,所以ASP.NET Core先后采用的三种承载方式都是采用这种模式。(本篇提供的实例已经汇总到《ASP.NET Core 6框架揭秘-实例演示版》)
蒋金楠
2022/05/09
1.1K0
2种方法实现ASP.NET Core 6自定义配置使用kestrel server
Kestrel 是一个跨平台的、开源的、轻量级的 HTTP 服务器,它是 ASP.NET Core 的默认 Web 服务器。Kestrel 是跨平台的,因此可以在不同的操作系统上运行,包括 Windows、Linux 和 macOS。本文主要介绍ASP.NET Core 6中kestrel 的配置及使用。
郑子铭
2023/11/30
1.3K0
2种方法实现ASP.NET Core 6自定义配置使用kestrel server
ASP.NET Core 2.2 : 二十二. 多样性的配置方式
    大多数应用都离不开配置,本章将介绍ASP.NET Core中常见的几种配置方式及系统内部实现的机制。(ASP.NET Core 系列目录)
FlyLolo
2019/09/23
6270
ASP.NET Core 2.2 : 二十二. 多样性的配置方式
从头编写 asp.net core 2.0 web api 基础框架 (3)
Github源码地址:https://github.com/solenovex/Building-asp.net-core-2-web-api-starter-template-from-scratc
solenovex
2018/03/01
1.6K0
从头编写 asp.net core 2.0 web api 基础框架 (3)
ASP.NET Core 的 WebApplication 类
ASP.NET Core 提供了 3 个主机类(Host)。这些类用于配置应用、管理生命周期和启动 Web 服务。
郑子铭
2025/06/11
810
ASP.NET Core 的 WebApplication 类
ASP.NET Core管道详解[6]: ASP.NET Core应用是如何启动的?[下篇]
要承载一个ASP.NET Core应用,只需要将GenericWebHostService服务注册到承载系统中即可。但GenericWebHostService服务具有针对其他一系列服务的依赖,所以在注册该承载服务之前需要先完成对这些依赖服务的注册。针对GenericWebHostService及其依赖服务的注册是借助GenericWebHostBuilder对象来完成的。
蒋金楠
2020/12/07
2.5K0
ASP.NET Core appsettings.json文件(9)《从零开始学ASP.NET CORE MVC》:
在本视频中,我们将讨论ASP.NET Core 项目中appsettings.json文件的重要性。
角落的白板报
2019/05/05
1.5K0
ASP.NET Core 2.0 : 五.服务是如何加载并运行的, Kestrel、配置与环境
"跨平台"后的ASP.Net Core是如何接收并处理请求的呢? 它的运行和处理机制和之前有什么不同? 本章从"宏观"到"微观"地看一下它的结构以及不同时期都干了些什 本章主要内容如下: ASP.NE
FlyLolo
2018/05/17
1.1K0
asp.net core 系列之静态文件
静态文件,例如HTML,CSS, images和JavaScript. 要想直接被客户端访问,需要做一些配置。
Vincent-yuan
2019/09/11
1.9K0
asp.net core 系列之静态文件
在ASP.NET Core应用中如何设置和获取与执行环境相关的信息?
HostingEnvironment是承载应用当前执行环境的描述,它是对所有实现了IHostingEnvironment接口的所有类型以及对应对象的统称。如下面的代码片段所示,一个HostingEnvironment对象承载的执行环境的描述信息体现在定义这个接口的6个属性上。ApplicationName和EnvironmentName分别代表当前应用的名称和执行环境的名称。WebRootPath和ContentRootPath是指向两个根目录的路径,前者指向的目录用于存放可供外界通过HTTP请求访问的资源
蒋金楠
2018/02/07
3.9K0
在ASP.NET Core应用中如何设置和获取与执行环境相关的信息?
ASP.NET Core应用基本编程模式[5]:如何放置你的初始化代码
一个ASP.NET Core应用的核心就是由一个服务器和一组有序中间件组成的请求处理管道,服务器只负责监听、接收和分发请求,以及最终完成对请求的响应,所以一个ASP.NET Core应用针对请求的处理能力和处理方式由注册的中间件来决定。一个ASP.NET Core在启动过程中的核心工作就是注册中间件,本节主要介绍应用启动过程中以中间件注册为核心的初始化工作。
蒋金楠
2020/11/24
1.3K0
ASP.NET Core应用基本编程模式[5]:如何放置你的初始化代码
ASP.NET Core静态文件的使用方法
静态文件(HTML,CSS,图片和Javascript之类的资源)会被ASP.NET Core应用直接提供给客户端。
米米素材网
2022/07/23
1.6K0
ASP.NET Core静态文件的使用方法
推荐阅读
相关推荐
一题多解,ASP.NET Core应用启动初始化的N种方案[上篇]
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验