[接上篇]“天下大勢,分久必合,合久必分”,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對象暴露出來,所以任何的服務注冊都可以利用這個屬性來完成。
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,并將其內容作為請求的響應。
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資源文件的根目錄。
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對象來完成。我們利用這個對象將表示“子環境名稱”的承載配置進行了設置。
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配置選項,改用三個對應的環境變量。由于環境變量會默認作為配置源,所以自然也可以利用環境變量設置子環境名稱。
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資源文件根目錄進行了設置。
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接口)對象嗎?我們是否可以按照如下的方式利用這個對象來設置承載環境相呢。很遺憾,我們同樣會得到上面這個錯誤。
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對象按照如下的方式直接修改與承載環境相關的配置呢?
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方法來設置子環境名稱。
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方法進行設置。
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方法依然是可以使用的,所以演示實例針對應用配置的設置可以改寫成如下兩種形式。
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();
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方法依然是可以使用的,所以演示實例針對服務的注冊可以改寫成如下兩種形式。
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();
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方法來注冊中間件,比如將我們的演示實例改寫成如下的形式。
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中也不再被支持。
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異常。