毕业设计选择做网站的意义,程序外包,dw下载免费中文版,宁夏免费做网站SP.NET Core 是新一代的 ASP.NET#xff0c;第一次出现时代号为 ASP.NET vNext#xff0c;后来命名为ASP.NET 5#xff0c;随着它的完善与成熟#xff0c;最终命名为 ASP.NET Core#xff0c;表明它不是 ASP.NET 的升级#xff0c;而是一个重新设计的Web开发框架。而它一…SP.NET Core 是新一代的 ASP.NET第一次出现时代号为 ASP.NET vNext后来命名为ASP.NET 5随着它的完善与成熟最终命名为 ASP.NET Core表明它不是 ASP.NET 的升级而是一个重新设计的Web开发框架。而它一个非常重要的变化就是它不再依赖于IIS而是一个独立的自寄宿的控制台应用程序这也是它可以跨平台的基石而本文就来详细探讨一下 ASP.NET Core 的启动过程。
目录
本系列文章将会从源码分析来讲解 ASP.NET Core 的运行原理分为以下几个章节
ASP.NET Core 运行原理解剖[1]:Hosting(Current)
ASP.NET Core 运行原理解剖[2]:Hosting补充之配置介绍
ASP.NET Core 运行原理解剖[3]:Middleware-请求管道的构成
ASP.NET Core 运行原理解剖[4]:进入HttpContext的世界(待续)
ASP.NET Core 运行原理解剖[5]:Authentication(待续)
前言
我们先回顾一下以前的 ASP.NET 是怎么来运行的 ASP.NET 是严重依赖于IIS的System.Web 中有很多方法都是直接调用的 IIS API并且它还是驻留在IIS进程中的。而 ASP.NET Core 的运行则是一个完全独立的控制台程序它有自己的 Kestrel Server可以直接对外部提供服务。
不过 Kestrel 的功能相对较于简单所以我们还是需要一个反向代理服务器将 Kestrel 服务器保护起来。而微软也为我们提供了 UseIISIntegration 方法方便与IIS进行集成。因此在 Windows 下通常还是使用IIS来部署那么此时与 ASP.NET 的运行方式又有什么区别呢 通过上图可以很清楚的明白它们的区别。在 ASP.NET Core 中IIS 是通过 HTTP 的方式来调用我们的 ASP.NET Core 程序。而部署在IIS中时并不需要我们手动来启动 ASP.NET Core 的控制台程序这是因为IIS新增了一个 AspNetCoreModule 模块它负责 ASP.NET Core 程序的启动与停止并能监听 ASP.NET Core 程序的状态在我们的应用程序意外崩溃时重新启动。
下面开始进入正题进入到 ASP.NET Core 的代码中去。
WebHost的创建
对于一个程序控制台程序来说它的入口点便是 Program 中的 Main 方法ASP.NET Core 程序自然也不例外
public class Program{ public static void Main(string[] args) {BuildWebHost(args).Run();} public static IWebHost BuildWebHost(string[] args) WebHost.CreateDefaultBuilder(args).UseStartupStartup().Build();
}
WebHost.CreateDefaultBuilder 是在 2.0 中新增的在 MetaPackages 程序集中代码如下
public static IWebHostBuilder CreateDefaultBuilder(string[] args){ var builder new WebHostBuilder().UseKestrel().UseContentRoot(Directory.GetCurrentDirectory()).ConfigureAppConfiguration((hostingContext, config) { var env hostingContext.HostingEnvironment; config.AddJsonFile(appsettings.json, optional: true, reloadOnChange: true) .AddJsonFile($appsettings.{env.EnvironmentName}.json, optional: true, reloadOnChange: true); if (env.IsDevelopment()){ 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) {logging.AddConfiguration(hostingContext.Configuration.GetSection(Logging));logging.AddConsole();logging.AddDebug();}).UseIISIntegration().UseDefaultServiceProvider((context, options) {options.ValidateScopes context.HostingEnvironment.IsDevelopment();}); return builder;
}
它只是用来简化我们的代码做了一些基本的配置
注册 Kestrel 中间件指定 WebHost 要使用的 ServerHTTP服务器。设置 Content 根目录将当前项目的根目录作为 ContentRoot 的目录。读取 appsettinggs.json 配置文件开发环境下的 UserSecrets 以及环境变量和命令行参数。读取配置文件中的 Logging 节点对日志系统进行配置。添加 IISIntegration 中间件。设置开发环境下 ServiceProvider 的 ValidateScopes 为 true避免直接在 Configure 方法中获取 Scope 实例。
然后指定 Startup 类最后通过 Build 方法创建 WebHost 对象而WebHostBuilder 的代码较多感兴趣的可以去看完整代码 WebHostBuilder而在这里我只展示部分代码片段来帮助理解
public IWebHost Build(){ var hostingServices BuildCommonServices(out var hostingStartupErrors); var applicationServices hostingServices.Clone(); var hostingServiceProvider hostingServices.BuildServiceProvider();AddApplicationServices(applicationServices, hostingServiceProvider);
}
Build 中的 BuildCommonServices 方法主要有两个功能
首先在程序集中查找 HostingStartupAttribute:
if (!_options.PreventHostingStartup)
{ var exceptions new ListException(); // Execute the hosting startup assembliesforeach (var assemblyName in _options.HostingStartupAssemblies){ var assembly Assembly.Load(new AssemblyName(assemblyName)); foreach (var attribute in assembly.GetCustomAttributesHostingStartupAttribute()){ var hostingStartup (IHostingStartup)Activator.CreateInstance(attribute.HostingStartupType);hostingStartup.Configure(this);}}
}
HostingStartupAttribute 给我们一个在其它程序集中做一些启动配置的机会在我们进行多层开发及模块化的时候非常有用下一站会详细解释。
然后便是查找我们的 Startup 类
if (!string.IsNullOrEmpty(_options.StartupAssembly))
{ var startupType StartupLoader.FindStartupType(_options.StartupAssembly, _hostingEnvironment.EnvironmentName); if (typeof(IStartup).GetTypeInfo().IsAssignableFrom(startupType.GetTypeInfo())){services.AddSingleton(typeof(IStartup), startupType);} else{services.AddSingleton(typeof(IStartup), sp { var hostingEnvironment sp.GetRequiredServiceIHostingEnvironment(); var methods StartupLoader.LoadMethods(sp, startupType, hostingEnvironment.EnvironmentName); return new ConventionBasedStartup(methods);});}
}
首先是判断是否有 _options.StartupAssembly对应配置文件中的 startupAssembly 如果我们没有设置那便是空的并不会执行上面代码。通常我们会使用 UseStartupStartup 的方法来注册 Startup 类而他们的作用是一样的都是将我们的 Startup 类做为一个单例注册到了 DI 系统。
而最终 BuildCommonServices 返回一个 IServiceCollection用于构建 hostingServiceProvider
var hostingServices BuildCommonServices(out var hostingStartupErrors);var applicationServices hostingServices.Clone();var hostingServiceProvider hostingServices.BuildServiceProvider();
接下来创建 WebHost :
public IWebHost Build(){ var host new WebHost(applicationServices,hostingServiceProvider,_options,_config,hostingStartupErrors);}host.Initialize(); return host;
}
这里需要说明的hostingServiceProvider 是 ASP.NET Core 中的第一个 ServiceProvider也是根 ServiceProvider但它是在我们的 Starpup 类执行之前创建的也就是说并不会包含我们在 ConfigureServices 中注册的服务但包含使用 HostingStartupAttribute 注册的服务。
WebHost启动流程
在上一步创建完 WebHost 之后便调用它的 Run 方法而 Run 方法再去调用 WebHost 的 StartAsync 方法开始 ASP.NET Core 的启动工作主要包含以下几个步骤
1. 初始化构建 RequestDelegate
RequestDelegate 是我们的应用程序处理请求输出响应的整个过程也就是我们的 ASP.NET Core 请求管道。
而它有如下定义
public delegate Task RequestDelegate(HttpContext context);
这里不再对 RequestDelegate 进行过多的介绍以后会详细解释。
1.1. 调用 Startup 中的 ConfigureServices 方法
在前面介绍过我们的 Startup 类已经注册到了 ASP.NET Coer 的 DI 系统中因此可以直接从 DI 中获取
private IStartup _startup;private IServiceProvider _applicationServices;_startup _hostingServiceProvider.GetRequiredServiceIStartup();_applicationServices _startup.ConfigureServices(_applicationServiceCollection);
这里使用的 _hostingServiceProvider 是我们在 WebHost 中创建的根 ServieProvider。
1.2. 初始化 Http Server
Server 是一个HTTP服务器负责HTTP的监听接收一组 FeatureCollection 类型的原始请求并将其包装成 HttpContext 以供我们的应用程序完成响应的处理。
public interface IServer : IDisposable{IFeatureCollection Features { get; }Task StartAsyncTContext(IHttpApplicationTContext application, CancellationToken cancellationToken); Task StopAsync(CancellationToken cancellationToken);
}
而上面注册的 Kestrel 便是默认的 Server
public static IWebHostBuilder UseKestrel(this IWebHostBuilder hostBuilder){hostBuilder.UseLibuv(); return hostBuilder.ConfigureServices(services {services.AddTransientIConfigureOptionsKestrelServerOptions, KestrelServerOptionsSetup();services.AddSingletonIServer, KestrelServer();});
}
Server的初始化主要是配置要监听的地址
private void EnsureServer(){ if (Server null){Server _applicationServices.GetRequiredServiceIServer(); var serverAddressesFeature Server.Features?.GetIServerAddressesFeature(); var addresses serverAddressesFeature?.Addresses; if (addresses ! null !addresses.IsReadOnly addresses.Count 0){ var urls _config[WebHostDefaults.ServerUrlsKey] ?? _config[DeprecatedServerUrlsKey]; if (!string.IsNullOrEmpty(urls)){serverAddressesFeature.PreferHostingUrls WebHostUtilities.ParseBool(_config, WebHostDefaults.PreferHostingUrlsKey); foreach (var value in urls.Split(new[] { ; }, StringSplitOptions.RemoveEmptyEntries)){addresses.Add(value);}}}}
}
Addresses 默认是通过在 launchSettings.json 中来查找的。
1.3. 创建 IApplicationBuilder
IApplicationBuilder 用于构建应用程序的请求管道也就是生成 RequestDelegate有如下定义
public interface IApplicationBuilder{IServiceProvider ApplicationServices { get; set; }IFeatureCollection ServerFeatures { get; }IDictionarystring, object Properties { get; } RequestDelegate Build(); IApplicationBuilder New(); IApplicationBuilder Use(FuncRequestDelegate, RequestDelegate middleware);
}
而它的创建过程是通过 ApplicationBuilderFactory 来创建的
var builderFactory _applicationServices.GetRequiredServiceIApplicationBuilderFactory(); var builder builderFactory.CreateBuilder(Server.Features);
builder.ApplicationServices _applicationServices;
IApplicationBuilderFactory 的默认实现 ApplicationBuilderFactory
public IApplicationBuilder CreateBuilder(IFeatureCollection serverFeatures){ return new ApplicationBuilder(_serviceProvider, serverFeatures);
}
ApplicationBuilder 的实现方式就不在这里多说了在讲中间件的时候再来细说。
1.4. 配置 IApplicationBuilder
我们比较的熟悉的是在 Startup 类的 Configure 方法中对 IApplicationBuilder 进行配置其实还有一个 IStartupFilter 也可以用来配置 IApplicationBuilder并且在 Startup 类的Configure 方法之前执行
var startupFilters _applicationServices.GetServiceIEnumerableIStartupFilter();
ActionIApplicationBuilder configure _startup.Configure;foreach (var filter in startupFilters.Reverse())
{configure filter.Configure(configure);
}configure(builder);
然后调用 IApplicationBuilder 的 Build 方法便完成了 RequestDelegate 的创建 private RequestDelegate BuildApplication(){... return builder.Build();
}
2. 启动 Server监听请求并响应
Server 本身是并不清楚 HttpContext 的细节的因此它需要接收一个 IHttpApplication 类型的参数来负责 HttpContext 的创建由如下定义
public interface IHttpApplicationTContext
{ TContext CreateContext(IFeatureCollection contextFeatures); Task ProcessRequestAsync(TContext context); void DisposeContext(TContext context, Exception exception);
}
它的默认实现是 HostingApplication 类而 ProcessRequestAsync 方法则调用我们上面创建的 RequestDelegate 委托来完成对 HttpContext 的处理
public class HostingApplication : IHttpApplicationHostingApplication.Context
{ private readonly RequestDelegate _application; public Task ProcessRequestAsync(Context context) { return _application(context.HttpContext);}
}
最后启动 Server
var httpContextFactory _applicationServices.GetRequiredServiceIHttpContextFactory();var hostingApp new HostingApplication(_application, _logger, diagnosticSource, httpContextFactory);await Server.StartAsync(hostingApp, cancellationToken).ConfigureAwait(false);
Server 会绑定一个监听端口注册HTTP连接事件最终交给 Http2StreamTContext 来处理通过上面的 hostingApp 来切入到我们的应用程序中完成整个请求的处理
public class Http2StreamTContext : Http2Stream{ private readonly IHttpApplicationTContext _application; public override async Task ProcessRequestAsync() {... var context _application.CreateContext(this); try{ await _application.ProcessRequestAsync(context);...} finally{_application.DisposeContext(context, _applicationException);...}...}
}
3. 启动 HostedService
HostedService 为我们提供一个注册后台运行服务的机会它会在随着我们的 ASP.NET Core 程序启动而启动并在 ASP.NET Core 停止时进行优雅的关闭有如下定义
public interface IHostedService{ Task StartAsync(CancellationToken cancellationToken); Task StopAsync(CancellationToken cancellationToken);
}
而它是通过 HostedServiceExecutor 来执行的
public class HostedServiceExecutor{ private readonly IEnumerableIHostedService _services; public async Task StartAsync(CancellationToken token) { await ExecuteAsync(service service.StartAsync(token));} public async Task StopAsync(CancellationToken token) { await ExecuteAsync(service service.StopAsync(token));} private async Task ExecuteAsync(FuncIHostedService, Task callback) { foreach (var service in _services){ await callback(service);}}
}
WebHost 会调用 HostedServiceExecutor 的 StartAsync 从而完成对 HostedService 的启动
_applicationLifetime _applicationServices.GetRequiredServiceIApplicationLifetime() as ApplicationLifetime;
_hostedServiceExecutor _applicationServices.GetRequiredServiceHostedServiceExecutor();// Fire IApplicationLifetime.Started_applicationLifetime?.NotifyStarted();// Fire IHostedService.Startawait _hostedServiceExecutor.StartAsync(cancellationToken).ConfigureAwait(false);
这里还有对 IApplicationLifetime 启动事件的触发以后会介绍一下 IApplicationLifetime 的用途。
到此 WebHost 的整个启动过程介绍完毕。
总结
本文粗略地介绍了一下 ASP.NET Core 中 WebHost 创建及启动它也是 ASP.NET Core 中的宿主包含 HttpServer 的启动与监听而其中也涉及到了很多关键点对我们以后的开发非常有用由于篇幅有限下一章再来介绍一些本文没有解释清楚的概念。
参考文章
Publishing-and-Running-ASPNET-Core-Applications-with-IIS
相关文章
.NET Core 2.0 正式发布信息汇总.NET Standard 2.0 特性介绍和使用指南.NET Core 2.0 的dll实时更新、https、依赖包变更问题及解决.NET Core 2.0 特性介绍和使用指南Entity Framework Core 2.0 新特性体验 PHP under .NET Core.NET Core 2.0使用NLog升级项目到.NET Core 2.0在Linux上安装Docker并成功部署解决Visual Studio For Mac Restore失败的问题ASP.NET Core 2.0 特性介绍和使用指南.Net Core下通过Proxy 模式 使用 WCF.NET Core 2.0 开源Office组件 NPOIASP.NET Core Razor页面 vs MVCRazor Page–Asp.Net Core 2.0新功能 Razor Page介绍MySql 使用 EF Core 2.0 CodeFirst、DbFirst、数据库迁移Migration介绍及示例.NET Core 2.0迁移技巧之web.config配置文件asp.net core MVC 过滤器之ExceptionFilter过滤器(一)ASP.NET Core 使用Cookie验证身份ASP.NET Core MVC – Tag Helpers 介绍ASP.NET Core MVC – Caching Tag HelpersASP.NET Core MVC – Form Tag HelpersASP.NET Core MVC – 自定义 Tag HelpersASP.NET Core MVC – Tag Helper 组件
原文地址http://www.cnblogs.com/RainingNight/p/hosting-in-asp-net-core.html .NET社区新闻深度好文微信中搜索dotNET跨平台或扫描二维码关注