※This article is based on .NET 7
标准提供 WebApplication 和 WebApplicationBuilder 两个类,从的名字上大致也能猜测到
那么在ASP.NET Core框架的语义下应用(Application)可以这样来理解:既然Pipeline = Server + HttpHandler,那么用来处理请求的HttpHandler不就承载了当前应用的所有职责吗?
那么HttpHandler就等于Application,由于HttpHandler通过RequestDelegate表示,那么由ApplicationBuilder构建的Application就是一个RequestDelegate对象。
由于表示HttpHandler的RequestDelegate是由注册的中间件来构建的,所以ApplicationBuilder还具有注册中间件的功能。基于ApplicationBuilder具有的这两个基本职责,我们可以将对应的接口定义成如下的形式。Use方法用来注册提供的中间件,Build方法则将注册的中间件构建成一个RequestDelegate对象。
public interface IApplicationBuilder { IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware); RequestDelegate Build(); }
如下所示的是针对该接口的具体实现。我们利用一个列表来保存注册的中间件,所以Use方法只需要将提供的中间件添加到这个列表中即可。当Build方法被调用之后,我们只需按照与注册相反的顺序依次执行表示中间件的Func<RequestDelegate, RequestDelegate>对象就能最终构建出代表HttpHandler的RequestDelegate对象。
public class ApplicationBuilder : IApplicationBuilder { private readonly List<Func<RequestDelegate, RequestDelegate>> _middlewares = new List<Func<RequestDelegate, RequestDelegate>>(); public RequestDelegate Build() { _middlewares.Reverse(); return httpContext => { RequestDelegate next = _ => { _.Response.StatusCode = 404; return Task.CompletedTask; }; foreach (var middleware in _middlewares) { next = middleware(next); } return next(httpContext); }; } public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware) { _middlewares.Add(middleware); return this; } }
在调用第一个中间件(最后注册)的时候,我们创建了一个RequestDelegate作为输入,后者会将响应状态码设置为404。所以如果http://ASP.NET Core应用在没有注册任何中间的情况下总是会返回一个404的响应。如果所有的中间件在完成了自身的请求处理任务之后都选择将请求向后分发,同样会返回一个404响应。
Startup.cs
namespace WebApplication1 { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllers(); services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication1", Version = "v1" }); }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebApplication1 v1")); } app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } } }
通过代码来配置
var builder = WebApplication.CreateBuilder(args); // Configure the cert and the key builder.Configuration["Kestrel:Certificates:Default:Path"] = "cert.pem"; builder.Configuration["Kestrel:Certificates:Default:KeyPath"] = "key.pem"; var app = builder.Build(); app.Urls.Add("https://localhost:3000"); app.MapGet("/", () => "Hello World"); app.Run();
var builder = WebApplication.CreateBuilder(new WebApplicationOptions { ApplicationName = typeof(Program).Assembly.FullName, ContentRootPath = Directory.GetCurrentDirectory(), EnvironmentName = Environments.Staging }); Console.WriteLine($"Application Name: {builder.Environment.ApplicationName}"); Console.WriteLine($"Environment Name: {builder.Environment.EnvironmentName}"); Console.WriteLine($"ContentRoot Path: {builder.Environment.ContentRootPath}"); var app = builder.Build();
运行后:
:\MyProjects\DotNetLearning\.Net6\WebApplicationDemo>dotnet run 正在生成... Application Name: WebApplicationDemo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null Environment Name: Staging ContentRoot Path: D:\MyProjects\DotNetLearning\.Net6\WebApplicationDemo
除了代码改变之外,还可以通过如下的环境变量来改变:
或者通过命令行参数来改变:
var builder = WebApplication.CreateBuilder(args); builder.Configuration.AddIniFile("appsettings.ini"); var app = builder.Build();
读取配置 默认按照如下的顺序读取配置:
读取配置的实例:
var builder = WebApplication.CreateBuilder(args); // Reads the ConnectionStrings section of configuration and looks for a sub key called Todos var connectionString = builder.Configuration.GetConnectionString("Todos"); Console.WriteLine($"My connection string is {connectionString}"); var app = builder.Build();
var builder = WebApplication.CreateBuilder(args); if (builder.Environment.IsDevelopment()) { Console.WriteLine($"Running in development"); } var app = builder.Build();
var builder = WebApplication.CreateBuilder(args); // Configure JSON logging to the console builder.Logging.AddJsonConsole(); var app = builder.Build();
var builder = WebApplication.CreateBuilder(args); // Add the memory cache services builder.Services.AddMemoryCache(); // Add a custom scoped service builder.Services.AddScoped<ITodoRepository, TodoRepository>(); var app = builder.Build();
默认情况下webroot是在相对路径下的wwwroot下,如果要改变这个路径,可以使用如下的方法:
var builder = WebApplication.CreateBuilder(args); // Look for static files in webroot builder.WebHost.UseWebRoot("webroot"); var app = builder.Build();
我们这里使用Autofac
var builder = WebApplication.CreateBuilder(args); builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()); // Register your own things directly with Autofac here. Don't // call builder.Populate(), that happens in AutofacServiceProviderFactory // for you. builder.Host.ConfigureContainer<ContainerBuilder>(builder => builder.RegisterModule(new MyApplicationModule())); var app = builder.Build();
中间件的添加都应该在WebApplication上完成
var app = WebApplication.Create(args); // Setup the file server to serve static files app.UseFileServer(); app.Run();
WebApplication默认启用了开发者异常页面
var app = WebApplication.Create(args); app.MapGet("/", () => throw new InvalidOperationException("Oops, the '/' route has thrown an exception.")); app.Run();
コメント:
}}