前往小程序,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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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
运行
复制
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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
Chrome开发者工具完全入门指南:零基础到日常调试
最常用图示说明:① Elements 元素 ② Console 控制台 ③ Sources 源代码来源 ④ Network 网络 ⑤ Performance 性能
小明互联网技术分享社区
2025/05/16
6510
Chrome开发者工具完全入门指南:零基础到日常调试
Chrome - JavaScript调试技巧总结(浏览器调试JS)
Chrome 是 Google 出品的一款非常优秀的浏览器,其内置了开发者工具(Windows 系统中按下 F12 即可开启),可以让我们方便地对 JavaScript 代码进行调试。
小蔚
2019/09/11
25.6K0
Chrome - JavaScript调试技巧总结(浏览器调试JS)
【干货】最全的JavaScript调试技巧总结,必看!
调试技巧,在任何一项技术研发中都可谓是必不可少的技能。掌握各种调试技巧,必定能在编码中起到事半功倍的效果。譬如,快速定位问题、降低故障概率、帮助分析逻辑错误等等。而在互联网前端开发越来越重要的今天,如何在前端开发中降低开发成本,提升工作效率,掌握前端开发调试技巧尤为重要。 老九君今天将为小伙伴们一一讲解各种前端JS调试技巧,也许有的小伙伴们已经熟练掌握,那让我们一起来温习,也许有的小伙伴还没见过这种调试方法,不妨一起来学习,也许有的小伙伴还尚不知如何调试,赶紧趁此机会填补空白。 骨灰级调试大师Alert 那
老九君
2018/03/01
2K0
【干货】最全的JavaScript调试技巧总结,必看!
(转)一探前端开发中的JS调试技巧
前言:调试技巧,在任何一项技术研发中都可谓是必不可少的技能。掌握各种调试技巧,必定能在工作中起到事半功倍的效果。譬如,快速定位问题、降低故障概率、帮助分析逻辑错误等等。而在互联网前端开发越来越重要的今天,如何在前端开发中降低开发成本,提升工作效率,掌握前端开发调试技巧尤为重要。 本文将一一讲解各种前端JS调试技巧,也许你已经熟练掌握,那让我们一起来温习,也许有你没见过的方法,不妨一起来学习,也许你尚不知如何调试,赶紧趁此机会填补空白。 骨灰级调试大师Alert 那还是互联网刚刚起步的时代,网页前端还主要以内
前端黑板报
2018/01/29
2.9K0
(转)一探前端开发中的JS调试技巧
Chrome浏览器调试技巧大全!
注:本文测试、截图均为Edge浏览器(内核是Chromium),浏览器内核可了解《有哪些浏览器/内核?[1]》
zz_jesse
2024/07/04
4580
Chrome浏览器调试技巧大全!
JavaScript 逆向爬虫中的浏览器调试常见技巧
这是「进击的Coder」的第 592 篇技术分享 作者:崔庆才 “注:本文来自《Python3网络爬虫开发实战(第二版)》一书。 ” 现在越来越多的网站也已经应用了这些技术对其数据接口进行了保护,在做爬虫时如果我们遇到了这种情况,我们可能就不得不硬着头皮来去想方设法找出其中隐含的关键逻辑了,这个过程我们可以称之为 JavaScript 逆向。 既然我们要做 JavaScript 逆向,那少不了要用到浏览器的开发者工具,因为网页是在浏览器中加载的,所以多数的调试过程也是在浏览器中完成的。 工欲善其事,必先利
崔庆才
2022/03/21
2.5K1
使用 Chrome DevTools 调试 JavaScript
不要再使用 console.log! 学会在 Chrome Developer Tools 中使用断点来调试代码。 作为一名新的开发人员,发现和修复 bug 挺难的。 您可能会试图随意使用 console.log() 来调试代码使代码正常工作。 不要再这样了。 这篇文章将讲述正确调试的方法! 您将了解如何使用 Chrome 开发人员工具来设置断点并逐步完成代码。这是更有效的在代码中查找和修复 bug 的方法。 本教程将向您展示如何调试一个具体 bug,您学到的方法将有助于您调试以后遇到的的 JavaS
wangxl
2018/03/29
2.5K0
使用 Chrome DevTools 调试 JavaScript
Chrome控制台骚操作,知道这些事半功倍
Chrome 浏览器想必是每个前端工程师必备的利器之一,速度快、体积小、支持的特性也比其他浏览器多;除此之外,它还拥有强大的控制台功能,但很多开发者并没有用出控制台的精髓,只是使用 console.log();,其实控制台的功能远不止那么简单。
ConardLi
2019/09/08
1.6K0
【实践】Chrome浏览器客户端调试从入门到奔溃
不懂CHROME前端调试工具,遇到问题就叽叽喳喳问前端,显得很不专业。辉哥利用五一节日,补补功课,引用相关优质文章,把Chrome浏览器客户端调试的方法详细讲解一遍。
辉哥
2019/05/14
3.9K0
【实践】Chrome浏览器客户端调试从入门到奔溃
Chrome 开发者工具的小技巧
Chrome的开发者工具是个很强大的东西,相信程序员们都不会陌生,不过有些小功能可能并不为大众所知,所以,写下这篇文章罗列一下可能你所不知道的功能,有的功能可能会比较实用,有的则不一定,也欢迎大家补充交流。
happyJared
2018/12/26
5370
前端开发必备之Chrome开发者工具(上篇)
本文介绍的 Chrome 开发者工具基于 Chrome 65版本,如果你的 Chrome 开发者工具没有下文提到的那些内容,请检查下 Chrome 的版本 简介 Chrome 开发者工具是一套内置于 Google Chrome 中的Web开发和调试工具,可用来对网站进行迭代、调试和分析 打开 Chrome 开发者工具的方式有: 在Chrome菜单中选择 更多工具 > 开发者工具 在页面元素上右键点击,选择 “检查” 使用 快捷键 Ctrl+Shift+I (Windows) 或 Cmd+Opt+I (Mac
laixiangran
2018/04/24
9.2K0
前端开发必备之Chrome开发者工具(上篇)
【爬虫知识】浏览器开发者工具使用技巧总结
常见禁用开发者工具手段:https://blog.csdn.net/cplvfx/article/details/108518077
K哥爬虫
2021/08/03
2.5K0
【爬虫知识】浏览器开发者工具使用技巧总结
Chrome Devtools 高级调试指南(新)
前言 本文暂未涉及Performance面板的内容。 后续会单独出一篇,以下是目录: 常用命令和调试 黑盒脚本:Blackbox Script 控制台内置指令 远程调试WebView 1. Chrome Devtools 的用处 前端开发:开发预览、远程调试、性能调优、bug跟踪、断点调试等 后端开发:网络抓包、开发调试Response 测试:服务端API数据是否正确、审查页面元素样式及布局、页面加载性能分析、自动化测试 其他:安装扩展插件,如AdBlock、Gliffy、Axure等 2. 菜单面板拆解
前端劝退师
2019/10/13
2.9K0
分享高效使用 Chrome 浏览器调试前端代码的技巧
相信大部分前端同学都是用 Chrome 浏览器进行开发,这篇博客要分享的基本上是除了我们常用 console.log之外的,Chrome 开发者工具控制面板提供的调试方法~
夜尽天明
2019/07/10
1.2K0
分享高效使用 Chrome 浏览器调试前端代码的技巧
Web开发前端调试小技巧——Chrome控制台
Hello大家好,兔妞总觉得写代码很重要,调试也很重要,特别是前端,不光要看日志,还要调整样式,浏览器兔妞最喜欢用Chrome了,所以今天就为大家带来Chrome的调试技巧啦~~
萌兔IT
2019/07/25
2.2K0
Web开发前端调试小技巧——Chrome控制台
Chrome代码调试指南
安装此插件后,如果网页是由 react 开发的,那么开发者工具会多出一个 react 的选项,并且插件图标是点亮的。
Dreamy.TZK
2020/08/20
2.4K0
Chrome代码调试指南
在 Chrome DevTools 中调试 JavaScript
由浅入深说一说怎么样在 Chrome DevTools 中调试 JavaScript。
从入门到进错门
2020/03/17
5.8K0
Chrome开发者工具的小技巧
 Chrome的开发者工具是个很强大的东西,相信程序员们都不会陌生,不过有些小功能可能并不为大众所知,所以,写下这篇文章罗列一下可能你所不知道的功能,有的功能可能会比较实用,有的则不一定,也欢迎大家补
用户1289394
2018/02/28
1K0
Chrome开发者工具的小技巧
这几个控制台API能帮你调试Web应用
许多年前,调试JavaScript代码无非就是在要调试的函数内部插入几句console.log()而已。有时你会发现问题的根源并不在于你正在查看的函数,而是出现在这些函数调用的其它函数内部。结果就是更多的console.log()被插入到代码中。整个过程通常还伴随着不时的吐槽。
疯狂的技术宅
2019/03/27
1.2K0
这几个控制台API能帮你调试Web应用
使用 Chrome DevTools 调试 JavaScript
作为一名新的开发人员,发现和修复 bug 挺难的。您可能会试图随意使用 console.log() 来调试代码使代码正常工作。 不要再这样了。
用户5807183
2019/10/21
1.9K0
使用 Chrome DevTools 调试 JavaScript
推荐阅读
相关推荐
Chrome开发者工具完全入门指南:零基础到日常调试
更多 >
目录
  • 一、Minimal API
  • 二、推荐编程方式
  • 三、承载环境
  • 四、承载配置
  • 五、应用配置
  • 六、服务注册
  • 七、中间件注册
  • 八、Startup类型不再被支持
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档