ASP.NET Core技术研究-探秘Host主机启动过程
当我们将原有ASP.NET 应用程序升级迁移到ASP.NET Core之后,我们发现代码工程中多了两个类Program类和Startup类。 接下来我们详细探秘一下通用主机Host的启动过程。 一、Program类的Main函数入口 Program类最重要的功能就是启动主机,这里有一个主机的概念,是ASP.NET Core全新引入的。 主机负责应用程序启动和生存期管理。 同时,主机也是封装应用程序资源的对象:
启动主机时,它在 DI 容器中找到 IHostedService 的每个实现,然后调用 IHostedService.StartAsync。 在 web 应用中,其中一个 IHostedService 的实现是启动 HTTP 服务器实现的 web 服务。这里的HTTP服务器默认是Kestrel。 即:ASP.NET Core主机启动时,会启动一个HTTP服务器,默认是Kestrel。启动后监听并响应某个端口的HTTP请求。 我们继续看Program类的代码:? ?? ? ?从上述代码可以看到,Main函数中首先调用CreateHostBuilder方法,返回一个IHostBuilder。然后调用IHostBuilder.Build()方法完成 二、Host.CreateDefaultBuilder(args): 构造IHostBuilder的默认实现HostBuilder ? ?在CreateHostBuilder方法内部,首先调用了Host.CreateDefaultBuilder构造了一个HostBuilder,这个我们先看下源码,看看到底Host类内部做了什么操作: ? ?https://github.com/dotnet/extensions/blob/release/3.1/src/Hosting/Hosting/src/Host.cs public static IHostBuilder CreateDefaultBuilder(string[] args)
{
var builder = new HostBuilder();
builder.UseContentRoot(Directory.GetCurrentDirectory());
builder.ConfigureHostConfiguration(config =>
{
config.AddEnvironmentVariables(prefix: "DOTNET_");
if (args != null)
{
config.AddCommandLine(args);
}
});
builder.ConfigureAppConfiguration((hostingContext,config) =>
{
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json",optional: true,reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json",reloadOnChange: true);
if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName))
{
var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
if (appAssembly != null)
{
config.AddUserSecrets(appAssembly,optional: true);
}
}
config.AddEnvironmentVariables();
if (args != null)
{
config.AddCommandLine(args);
}
})
.ConfigureLogging((hostingContext,logging) =>
{
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
// IMPORTANT: This needs to be added *before* configuration is loaded,this lets
// the defaults be overridden by the configuration.
if (isWindows)
{
// Default the EventLogLoggerProvider to warning or above
logging.AddFilter<EventLogLoggerProvider>(level => level >= LogLevel.Warning);
}
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();
if (isWindows)
{
// Add the EventLogLoggerProvider on windows machines
logging.AddEventLog();
}
})
.UseDefaultServiceProvider((context,options) =>
{
var isDevelopment = context.HostingEnvironment.IsDevelopment();
options.ValidateScopes = isDevelopment;
options.ValidateOnBuild = isDevelopment;
});
return builder;
}
从上述代码中,可以看到CreateDefaultBuilder内部构造了一个HostBuilder,同时设置了:
? ?以上构造完成了HostBuilder,针对ASP.NET Core应用,代码继续调用了HostBuilder.ConfigureWebHostDefaults方法。 三、IHostBuilder.ConfigureWebHostDefaults:通过GenericWebHostBuilder对HostBuilder增加ASP.NET Core的运行时设置 ? ? 构造完成HostBuilder之后,针对ASP.NET Core应用,继续调用了HostBuilder.ConfigureWebHostDefaults方法。这是一个ASP.NET Core的一个扩展方法: ? ?? ? ? ? 我们继续看ConfigureWebHostDefaults扩展方法内部做了哪些事情: ? ? ? 源码连接:https://github.com/dotnet/aspnetcore/blob/master/src/DefaultBuilder/src/GenericHostBuilderExtensions.cs? ? ?? using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore;
namespace Microsoft.Extensions.Hosting
{
/// <summary>
/// Extension methods for configuring the IWebHostBuilder.
/// </summary>
public static class GenericHostBuilderExtensions
{
/// <summary>
/// Initializes a new instance of the <see cref="IWebHostBuilder"/> class with pre-configured defaults.
/// </summary>
/// <remarks>
/// The following defaults are applied to the <see cref="IWebHostBuilder"/>:
/// use Kestrel as the web server and configure it using the application's configuration providers,/// adds the HostFiltering middleware,/// adds the ForwardedHeaders middleware if ASPNETCORE_FORWARDEDHEADERS_ENABLED=true,/// and enable IIS integration.
/// </remarks>
/// <param name="builder">The <see cref="IHostBuilder" /> instance to configure</param>
/// <param name="configure">The configure callback</param>
/// <returns>The <see cref="IHostBuilder"/> for chaining.</returns>
public static IHostBuilder ConfigureWebHostDefaults(this IHostBuilder builder,Action<IWebHostBuilder> configure)
{
return builder.ConfigureWebHost(webHostBuilder =>
{
WebHost.ConfigureWebDefaults(webHostBuilder);
configure(webHostBuilder);
});
}
}
}
? 2020 GitHub,Inc.
?首先,通过类GenericHostWebHostBuilderExtensions,对IHostBuilder扩展一个方法:ConfigureWebHost:builder.ConfigureWebHost ? ? ?在这个扩展方法中实现了对IWebHostBuilder的依赖注入:即将GenericWebHostBuilder实例传入方法ConfigureWebHostDefaults内部 ? ? ?代码连接:https://github.com/dotnet/aspnetcore/blob/release/3.1/src/Hosting/Hosting/src/GenericHostWebHostBuilderExtensions.cs using System;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.Extensions.Hosting
{
public static class GenericHostWebHostBuilderExtensions
{
public static IHostBuilder ConfigureWebHost(this IHostBuilder builder,Action<IWebHostBuilder> configure)
{
var webhostBuilder = new GenericWebHostBuilder(builder);
configure(webhostBuilder);
builder.ConfigureServices((context,services) => services.AddHostedService<GenericWebHostService>());
return builder;
}
}
}
? ?通过GenericWebHostBuilder的构造函数GenericWebHostBuilder(buillder),将已有的HostBuilder增加了ASP.NET Core运行时设置。 ? ?可以参考代码:https://github.com/dotnet/aspnetcore/blob/release/3.1/src/Hosting/Hosting/src/GenericHost/GenericWebHostBuilder.cs ? ?。。。 ? ?先看到这,让我们回到ConfigureWebHostDefaults: ? ?将上面两段代码合并一下进行理解:ConfigureWebHostDefaults做了两件事情: ? ?1. 扩展IHostBuilder增加ConfigureWebHost,引入IWebHostBuilder的实现GenericWebHostBuilder,将已有的HostBuilder增加ASP.NET Core运行时的设置。 ? ?2. ConfigureWebHost代码中的configure(webhostBuilder):对注入的IWebHostBuilder,调用?WebHost.ConfigureWebDefaults(webHostBuilder),启用各类设置,如下代码解读:? 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();
}
? ? ? 内部实现了:
??3. 返回ConfigureWebHostDefaults代码中的configure(webHostBuilder):执行Program类中的webBuilder.UseStartup<Startup>(); ? 第三章节中,以上过程完成了IHostBuilder.ConfigureWebHostDefaults,通过GenericWebHostBuilder对HostBuilder增加ASP.NET Core的运行时设置。 ? 接下来继续Build和Run的过程。 四、CreateHostBuilder(args).Build().Run(); ??CreateHostBuilder返回的IHostBuilder,我们通过代码Debug,看一下具体的类型:Microsoft.Extensions.Hosting.HostBuilder,这样进一步验证了前三个章节的代码。 ?? ? 1. Build的过程 ? 先看下Build的源码:https://github.com/dotnet/extensions/blob/release/3.1/src/Hosting/Hosting/src/HostBuilder.cs ?? ? ? ? Build的过程主要完成了:
? 2. Run的过程 ? ? ?我们先通过Debug,看一下Host的信息:Microsoft.Extensions.Hosting.Internal.Host ? ? ? ? ? ? 这个Run方法也是一个扩展方法:HostingAbstractionsHostExtensions.Run ? ? ? 代码链接:https://github.com/dotnet/extensions/blob/release/3.1/src/Hosting/Abstractions/src/HostingAbstractionsHostExtensions.cs ? ? ?? ? ? ?其实内部转调的还是Host.StartAsync方法,在内部启动了DI依赖注入容器中所有注册的服务。 ? ? ?代码链接:https://github.com/dotnet/extensions/blob/release/3.1/src/Hosting/Hosting/src/Internal/Host.cs ? ? ? ? 整个Host主机的启动过程还是非常复杂的,我们只是简单的在代码层面研究了一遍,感觉只是有了个大致的轮廓,具体怎么执行的,是不是如上面代码的解释,还需要深入继续研究。 ? 参考链接: ? ?使用 IIS 在 Windows 上托管 ASP.NET Core ? ?https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/iis/?view=aspnetcore-3.1#iis-options&WT.mc_id=DT-MVP-5003918 ? ?配置 ASP.NET Core 以使用代理服务器和负载均衡器 ? ?https://docs.microsoft.com/zh-cn/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-3.1#forwarded-headers&WT.mc_id=DT-MVP-5003918 ? ?ASP.NET Core 中的 Kestrel Web 服务器实现 ? ?https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/servers/kestrel?view=aspnetcore-3.1#host-filtering&WT.mc_id=DT-MVP-5003918 ? ? ? 接下来下一篇文章准备把源码单步调试看看。加深对ASP.NET Core底层技术原理的理解,只有理解了底层技术实现,我们在应用层才能更好、正确的使用。 ? ? 周国庆 2020/4/6 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net – 如何将http请求转发到https网址
- .NET Core 3.0及ASP.NET Core 3.0 前瞻
- asp.net-mvc – 在OS X 10.7.4上的MonoDevelop中构建MVC4项
- asp.net-mvc – 使用RadioButtons的可空值布尔的MVC3 Edito
- asp.net – Visual Studio 2010图表控件 – 线条颜色
- asp.net – 使用StartMode =“AlwaysRunning”在ASP .NET 4
- ASP.NET CustomErrors – RemoteOnly,其中“remote”表示在
- 在ASP.NET属性中组合字符串
- asp.net – ObjectDataSource删除问题
- asp.net-mvc-4 – 创建和编辑MVC4的相同视图
- ASP.NET自定义404和500错误页面
- ASP.NET中的会话修复
- asp.net-mvc – 在ajax请求中返回PDF
- asp.net-mvc – 如何从验证摘要中删除列表
- asp.net-mvc – 用相同的动词重载asp.net MVC控制
- asp.net-mvc-4 – ASP.NET Active Directory搜索
- asp.net-mvc – Application_Error已调用,但没有
- asp.net-mvc – Razor – @ Html.Raw()仍在编码&
- asp.net-mvc – 具有相同签名的ASP.NET MVC 1.0控
- asp.net – 用于网页的SQL Reporting Services查