WebHost对象概念解释

WebHost

接口定义

  • IWebHost : 主机抽象

    • IFeatureCollection : 插件容器
    • IServiceProvider : 对象服务提供器
    • Start : 启动方法(同步)
    • StartAsync : 启动方法
    • StopAsync : 停止方法
  • IWebHostBuilder : 网站主机构建器

    • Build : 构建
    • ConfigureAppConfiguration : 配置应用配置文件
    • ConfigureServices : 配置服务
    • GetSetting : 读取单个配置值
    • UseSetting : 设置单个配置项

具体实现

  • GenericWebHostBuilder : 通用网站主机构造器(HostBuilder桥接器)

    • ConfigureHostConfiguration : 设置主机配置
    • ConfigureAppConfiguration : 设置应用配置
    • ConfigureServices : 设置服务
    • UseStartup : 使用StartUp配置启动
  • HostingStartupWebHostBuilder : 加载StartUp的网站主机构造器(装饰器)

静态类

  • WebHost
    • CreateDefaultBuilder() : 创建网站主机构建器

WebHost初始化

HostBuilder调用ConfigureWebHost拓展方法创建WebHostBuilderOptionsGenericWebHostBuilder

WebHostBuilder初始化

  • GenericWebHostBuilder

文件位置:GenericWebHostBuilder.cs

GenericWebHostBuilder装饰者类,构造函数传入参数HostBuilder,创建通用WebHostBuilder

  • ConfigureWebDefaults方法
  1. 注册 Kestrel 中间件,指定 WebHost 要使用的 Server(HTTP服务器)。
  2. 添加 IIS 和 IISIntegration 中间件。

文件位置:WebHost.cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
internal static void ConfigureWebDefaults(IWebHostBuilder builder)
{
builder.ConfigureAppConfiguration((ctx, cb) =>
{
if (ctx.HostingEnvironment.IsDevelopment())
{
StaticWebAssetsLoader.UseStaticWebAssets(ctx.HostingEnvironment, ctx.Configuration);
}
});
builder.UseKestrel((builderContext, options) =>
{
options.Configure(builderContext.Configuration.GetSection("Kestrel"));
})
.ConfigureServices((hostingContext, services) =>
{
// Fallback
services.PostConfigure<HostFilteringOptions>(options =>
{
if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)
{
// "AllowedHosts": "localhost;127.0.0.1;[::1]"
var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
// Fall back to "*" to disable.
options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });
}
});
// Change notification
services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>(
new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));

services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();

if (string.Equals("true", hostingContext.Configuration["ForwardedHeaders_Enabled"], StringComparison.OrdinalIgnoreCase))
{
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
// Only loopback proxies are allowed by default. Clear that restriction because forwarders are
// being enabled by explicit configuration.
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});

services.AddTransient<IStartupFilter, ForwardedHeadersStartupFilter>();
}

services.AddRouting();
})
.UseIIS()
.UseIISIntegration();
}

HostBuilderWebHostBuilderOptions通过构造函数传递给WebHostBuilder初始化对象。

WebHost构造器

创建WebHostBuilder通过拓展方法连接HostBuilder,把一些配置、服务、方法加进Host构建过程中。

GenericWebHostBuilder

构造函数里依次调HostBuilder的方法
ConfigureHostConfiguration合并HostWebHost的配置文件,并处理StartUp
ConfigureAppConfiguration委托调用HostingStartupWebHostBuilderConfigureAppConfiguration
ConfigureServices配置服务容器,添加DiagnosticListener,IHttpContextFactoryIMiddlewareFactoryIApplicationBuilderFactory等对象服务

HostingStartupWebHostBuilder``GenericWebHostBuilder

设置主机配置(ConfigureHostConfiguration)

把前缀是ASPNETCORE_的环境变量加到主机配置里,并创建WebHostBuilder装饰器HostingStartupWebHostBuilder来执行应用的StartUp文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var configBuilder = new ConfigurationBuilder()
.AddInMemoryCollection();

if (!options.SuppressEnvironmentConfiguration)
{
configBuilder.AddEnvironmentVariables(prefix: "ASPNETCORE_");
}

_config = configBuilder.Build();

_builder.ConfigureHostConfiguration(config =>
{
config.AddConfiguration(_config);

// We do this super early but still late enough that we can process the configuration
// wired up by calls to UseSetting
ExecuteHostingStartups();
});

设置应用配置(ConfigureAppConfiguration)

设置WebHost上下文WebHostContextHostingStartupWebHostBuilder负责把StartUp里的配置加到构建管道中

1
2
3
4
5
6
7
8
_builder.ConfigureAppConfiguration((context, configurationBuilder) =>
{
if (_hostingStartupWebHostBuilder != null)
{
var webhostContext = GetWebHostBuilderContext(context);
_hostingStartupWebHostBuilder.ConfigureAppConfiguration(webhostContext, configurationBuilder);
}
});

设置服务(ConfigureServices)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
_builder.ConfigureServices((context, services) =>
{
var webhostContext = GetWebHostBuilderContext(context);
var webHostOptions = (WebHostOptions)context.Properties[typeof(WebHostOptions)];

// Add the IHostingEnvironment and IApplicationLifetime from Microsoft.AspNetCore.Hosting
services.AddSingleton(webhostContext.HostingEnvironment);
#pragma warning disable CS0618 // Type or member is obsolete
services.AddSingleton((AspNetCore.Hosting.IHostingEnvironment)webhostContext.HostingEnvironment);
services.AddSingleton<IApplicationLifetime, GenericWebHostApplicationLifetime>();
#pragma warning restore CS0618 // Type or member is obsolete

services.Configure<GenericWebHostServiceOptions>(options =>
{
// Set the options
options.WebHostOptions = webHostOptions;
// Store and forward any startup errors
options.HostingStartupExceptions = _hostingStartupErrors;
});

// REVIEW: This is bad since we don't own this type. Anybody could add one of these and it would mess things up
// We need to flow this differently
var listener = new DiagnosticListener("Microsoft.AspNetCore");
services.TryAddSingleton<DiagnosticListener>(listener);
services.TryAddSingleton<DiagnosticSource>(listener);

services.TryAddSingleton<IHttpContextFactory, DefaultHttpContextFactory>();
services.TryAddScoped<IMiddlewareFactory, MiddlewareFactory>();
services.TryAddSingleton<IApplicationBuilderFactory, ApplicationBuilderFactory>();

// IMPORTANT: This needs to run *before* direct calls on the builder (like UseStartup)
_hostingStartupWebHostBuilder?.ConfigureServices(webhostContext, services);

// Support UseStartup(assemblyName)
if (!string.IsNullOrEmpty(webHostOptions.StartupAssembly))
{
try
{
var startupType = StartupLoader.FindStartupType(webHostOptions.StartupAssembly, webhostContext.HostingEnvironment.EnvironmentName);
UseStartup(startupType, context, services);
}
catch (Exception ex) when (webHostOptions.CaptureStartupErrors)
{
var capture = ExceptionDispatchInfo.Capture(ex);

services.Configure<GenericWebHostServiceOptions>(options =>
{
options.ConfigureApplication = app =>
{
// Throw if there was any errors initializing startup
capture.Throw();
};
});
}
}
});
ConfigureWebDefaults

设置应用配置(ConfigureAppConfiguration)

1
2
3
4
5
6
7
builder.ConfigureAppConfiguration((ctx, cb) =>
{
if (ctx.HostingEnvironment.IsDevelopment())
{
StaticWebAssetsLoader.UseStaticWebAssets(ctx.HostingEnvironment, ctx.Configuration);
}
});

设置站点服务器(UseKestrel)和设置服务(ConfigureServices)

加载配置文件Kestrel部分,启用Kestrel,设置服务中间件,头部转发、路由、过滤器、IIS服务等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
builder.UseKestrel((builderContext, options) =>
{
options.Configure(builderContext.Configuration.GetSection("Kestrel"));
})
.ConfigureServices((hostingContext, services) =>
{
// Fallback
services.PostConfigure<HostFilteringOptions>(options =>
{
if (options.AllowedHosts == null || options.AllowedHosts.Count == 0)
{
// "AllowedHosts": "localhost;127.0.0.1;[::1]"
var hosts = hostingContext.Configuration["AllowedHosts"]?.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
// Fall back to "*" to disable.
options.AllowedHosts = (hosts?.Length > 0 ? hosts : new[] { "*" });
}
});
// Change notification
services.AddSingleton<IOptionsChangeTokenSource<HostFilteringOptions>>(
new ConfigurationChangeTokenSource<HostFilteringOptions>(hostingContext.Configuration));

services.AddTransient<IStartupFilter, HostFilteringStartupFilter>();

if (string.Equals("true", hostingContext.Configuration["ForwardedHeaders_Enabled"], StringComparison.OrdinalIgnoreCase))
{
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
// Only loopback proxies are allowed by default. Clear that restriction because forwarders are
// being enabled by explicit configuration.
options.KnownNetworks.Clear();
options.KnownProxies.Clear();
});

services.AddTransient<IStartupFilter, ForwardedHeadersStartupFilter>();
}

services.AddRouting();
})
.UseIIS()
.UseIISIntegration();

Startup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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.AddControllersWithViews();
}

// 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();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}

站点服务初始化配置

RazorPage的路由解析服务

注册服务

文件位置:MvcRazorPagesMvcCoreBuilderExtensions.cs

  • AddRazorPages : 添加Razor Page服务
  • WithRazorPagesRoot : 设置Razor Page根目录

映射终端

文件位置:RazorPagesEndpointRouteBuilderExtensions.cs

  • MapRazorPages : 设置默认映射路由路径
  • MapFallbackToPage : 动态路由,找不到符合路径时自动跳转带设定路由
  • MapFallbackToAreaPage : 动态路由,找不到符合路径时自动跳转带设定二级路由
  • MapDynamicPageRoute : 动态路由,自定义路由规则

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();//设置路由规则
});
...
}

Controllers的路由解析服务

注册服务

文件位置:MvcServiceCollectionExtensions.cs

  • AddMvcCore : 最轻量,仅使用了路由解析必要服务,其他身份验证和资料验证等功能就需要另外引用
  • AddControllers : 次轻量,使用WebApi首选,比AddMvcCore多了资料、身份验证跟跨域等相关的服务
  • AddControllersWithViews : 包含AddControllers再加上View Page的服务,使用标准MVC服务可以使用
  • AddRazorPages : 使用RazorPage与部分AddControllers功能,前端使用RazorPage,不需要太多Api接口
  • AddMVC : 功能最全的MVC服务

映射终端

文件位置:ControllerEndpointRouteBuilderExtensions.cs

  • MapControllers : 将UseRouting的结果注册到终端
  • MapDefaultControllerRoute : 同MapControllers只是多设置一条{controller=Home}/{action=Idenx}/{id?}的预设路径
  • MapControllerRoute : 手动设定终端路由
  • MapAreaControllerRoute : 与MapControllerRouter同,路径多了Area的前缀
  • MapDynamicControllerRoute : 动态路由,自定义路由规则
  • MapFallbackToController : 动态路由,当找不到符合的路径时自动跳转到自定路由

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();//设置路由规则
});
...
}

SignalR的路由解析服务

注册服务

文件位置:SignalRDependencyInjectionExtensions.cs

  • AddSignalR : 添加SignalR服务
  • AddHubOptions : 设置Signal配置,通过HubOptions自定义配置

映射终端

文件位置:HubEndpointRouteBuilderExtensions.cs

  • MapHub : 设置SignalR默认映射路由路径

初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<SignalMethod>();//设置路由规则
});
...
}

gRPC的路由解析服务

注册服务

文件位置:GrpcServiceExtensions.cs

  • AddGrpc : 注册Grpc服务端服务
  • AddServiceOptions : 设置Grpc服务端配置

文件位置:GrpcClientServiceExtensions.cs

  • AddGrpcClient : 注册Grpc客户端服务

文件位置:GrpcHttpClientBuilderExtensions.cs

  • ConfigureChannel : 设置Grpc客户端的通道信息

映射终端

文件位置:GrpcEndpointRouteBuilderExtensions.cs

  • MapGrpcService : 设置Grpc服务端默认映射路由路径

服务端初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpc();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<GreeterService>();//设置路由规则
});
...
}

客户端初始化

1
2
3
4
5
6
7
8
9
10
public void ConfigureServices(IServiceCollection services)
{
services.AddGrpcClient<Greeter.GreeterClient>(o =>
{
o.Address = new Uri("https://localhost:5001");
})
.ConfigureChannel(o=>{
o.Credentials = new CustomCredentials();
});
}