标签:listener configure spro with miss token 初始 VID opp
IWebHost实现类WebHost
internal class WebHost : IWebHost, IAsyncDisposable
{
private static readonly string DeprecatedServerUrlsKey = "server.urls";
private readonly IServiceCollection _applicationServiceCollection;
private IStartup _startup;
private ApplicationLifetime _applicationLifetime;
private HostedServiceExecutor _hostedServiceExecutor;
private readonly IServiceProvider _hostingServiceProvider;
private readonly WebHostOptions _options;
private readonly IConfiguration _config;
private readonly AggregateException _hostingStartupErrors;
private IServiceProvider _applicationServices;
private ExceptionDispatchInfo _applicationServicesException;
private ILogger _logger = NullLogger.Instance;
private bool _stopped;
private bool _startedServer;
// Used for testing only
internal WebHostOptions Options => _options;
private IServer Server { get; set; }
public WebHost(
IServiceCollection appServices,
IServiceProvider hostingServiceProvider,
WebHostOptions options,
IConfiguration config,
AggregateException hostingStartupErrors)
{
if (appServices == null)
{
throw new ArgumentNullException(nameof(appServices));
}
if (hostingServiceProvider == null)
{
throw new ArgumentNullException(nameof(hostingServiceProvider));
}
if (config == null)
{
throw new ArgumentNullException(nameof(config));
}
_config = config;
_hostingStartupErrors = hostingStartupErrors;
_options = options;
_applicationServiceCollection = appServices;
_hostingServiceProvider = hostingServiceProvider;
_applicationServiceCollection.AddSingleton();
// There‘s no way to to register multiple service types per definition. See https://github.com/aspnet/DependencyInjection/issues/360
_applicationServiceCollection.AddSingleton(services
=> services.GetService() as IHostApplicationLifetime);
#pragma warning disable CS0618 // Type or member is obsolete
_applicationServiceCollection.AddSingleton(services
=> services.GetService() as AspNetCore.Hosting.IApplicationLifetime);
_applicationServiceCollection.AddSingleton(services
=> services.GetService() as Extensions.Hosting.IApplicationLifetime);
#pragma warning restore CS0618 // Type or member is obsolete
_applicationServiceCollection.AddSingleton();
}
public IServiceProvider Services
{
get
{
return _applicationServices;
}
}
public IFeatureCollection ServerFeatures
{
get
{
EnsureServer();
return Server?.Features;
}
}
// Called immediately after the constructor so the properties can rely on it.
public void Initialize()
{
try
{
EnsureApplicationServices();
}
catch (Exception ex)
{
// EnsureApplicationServices may have failed due to a missing or throwing Startup class.
if (_applicationServices == null)
{
_applicationServices = _applicationServiceCollection.BuildServiceProvider();
}
if (!_options.CaptureStartupErrors)
{
throw;
}
_applicationServicesException = ExceptionDispatchInfo.Capture(ex);
}
}
public void Start()
{
StartAsync().GetAwaiter().GetResult();
}
public virtual async Task StartAsync(CancellationToken cancellationToken = default)
{
HostingEventSource.Log.HostStart();
_logger = _applicationServices.GetRequiredService().CreateLogger("Microsoft.AspNetCore.Hosting.Diagnostics");
_logger.Starting();
var application = BuildApplication();
_applicationLifetime = _applicationServices.GetRequiredService();
_hostedServiceExecutor = _applicationServices.GetRequiredService();
// Fire IHostedService.Start
await _hostedServiceExecutor.StartAsync(cancellationToken).ConfigureAwait(false);
var diagnosticSource = _applicationServices.GetRequiredService();
var httpContextFactory = _applicationServices.GetRequiredService();
var hostingApp = new HostingApplication(application, _logger, diagnosticSource, httpContextFactory);
await Server.StartAsync(hostingApp, cancellationToken).ConfigureAwait(false);
_startedServer = true;
// Fire IApplicationLifetime.Started
_applicationLifetime?.NotifyStarted();
_logger.Started();
// Log the fact that we did load hosting startup assemblies.
if (_logger.IsEnabled(LogLevel.Debug))
{
foreach (var assembly in _options.GetFinalHostingStartupAssemblies())
{
_logger.LogDebug("Loaded hosting startup assembly {assemblyName}", assembly);
}
}
if (_hostingStartupErrors != null)
{
foreach (var exception in _hostingStartupErrors.InnerExceptions)
{
_logger.HostingStartupAssemblyError(exception);
}
}
}
private void EnsureApplicationServices()
{
if (_applicationServices == null)
{
EnsureStartup();
_applicationServices = _startup.ConfigureServices(_applicationServiceCollection);
}
}
private void EnsureStartup()
{
if (_startup != null)
{
return;
}
_startup = _hostingServiceProvider.GetService();
if (_startup == null)
{
throw new InvalidOperationException($"No application configured. Please specify startup via IWebHostBuilder.UseStartup, IWebHostBuilder.Configure, injecting {nameof(IStartup)} or specifying the startup assembly via {nameof(WebHostDefaults.StartupAssemblyKey)} in the web host configuration.");
}
}
private RequestDelegate BuildApplication()
{
try
{
_applicationServicesException?.Throw();
EnsureServer();
var builderFactory = _applicationServices.GetRequiredService();
var builder = builderFactory.CreateBuilder(Server.Features);
builder.ApplicationServices = _applicationServices;
var startupFilters = _applicationServices.GetService>();
Action configure = _startup.Configure;
foreach (var filter in startupFilters.Reverse())
{
configure = filter.Configure(configure);
}
configure(builder);
return builder.Build();
}
catch (Exception ex)
{
if (!_options.SuppressStatusMessages)
{
// Write errors to standard out so they can be retrieved when not in development mode.
Console.WriteLine("Application startup exception: " + ex.ToString());
}
var logger = _applicationServices.GetRequiredService>();
logger.ApplicationError(ex);
if (!_options.CaptureStartupErrors)
{
throw;
}
EnsureServer();
// Generate an HTML error page.
var hostingEnv = _applicationServices.GetRequiredService();
var showDetailedErrors = hostingEnv.IsDevelopment() || _options.DetailedErrors;
var model = new ErrorPageModel
{
RuntimeDisplayName = RuntimeInformation.FrameworkDescription
};
var systemRuntimeAssembly = typeof(System.ComponentModel.DefaultValueAttribute).GetTypeInfo().Assembly;
var assemblyVersion = new AssemblyName(systemRuntimeAssembly.FullName).Version.ToString();
var clrVersion = assemblyVersion;
model.RuntimeArchitecture = RuntimeInformation.ProcessArchitecture.ToString();
var currentAssembly = typeof(ErrorPage).GetTypeInfo().Assembly;
model.CurrentAssemblyVesion = currentAssembly
.GetCustomAttribute()
.InformationalVersion;
model.ClrVersion = clrVersion;
model.OperatingSystemDescription = RuntimeInformation.OSDescription;
model.ShowRuntimeDetails = showDetailedErrors;
if (showDetailedErrors)
{
var exceptionDetailProvider = new ExceptionDetailsProvider(
hostingEnv.ContentRootFileProvider,
sourceCodeLineCount: 6);
model.ErrorDetails = exceptionDetailProvider.GetDetails(ex);
}
else
{
model.ErrorDetails = new ExceptionDetails[0];
}
var errorPage = new ErrorPage(model);
return context =>
{
context.Response.StatusCode = 500;
context.Response.Headers[HeaderNames.CacheControl] = "no-cache";
return errorPage.ExecuteAsync(context);
};
}
}
private void EnsureServer()
{
if (Server == null)
{
Server = _applicationServices.GetRequiredService();
var serverAddressesFeature = Server.Features?.Get();
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);
}
}
}
}
}
public async Task StopAsync(CancellationToken cancellationToken = default)
{
if (_stopped)
{
return;
}
_stopped = true;
_logger.Shutdown();
var timeoutToken = new CancellationTokenSource(Options.ShutdownTimeout).Token;
if (!cancellationToken.CanBeCanceled)
{
cancellationToken = timeoutToken;
}
else
{
cancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken).Token;
}
// Fire IApplicationLifetime.Stopping
_applicationLifetime?.StopApplication();
if (Server != null && _startedServer)
{
await Server.StopAsync(cancellationToken).ConfigureAwait(false);
}
// Fire the IHostedService.Stop
if (_hostedServiceExecutor != null)
{
await _hostedServiceExecutor.StopAsync(cancellationToken).ConfigureAwait(false);
}
// Fire IApplicationLifetime.Stopped
_applicationLifetime?.NotifyStopped();
HostingEventSource.Log.HostStop();
}
public void Dispose()
{
DisposeAsync().ConfigureAwait(false).GetAwaiter().GetResult();
}
public async ValueTask DisposeAsync()
{
if (!_stopped)
{
try
{
await StopAsync().ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.ServerShutdownException(ex);
}
}
await DisposeServiceProviderAsync(_applicationServices).ConfigureAwait(false);
await DisposeServiceProviderAsync(_hostingServiceProvider).ConfigureAwait(false);
}
private async ValueTask DisposeServiceProviderAsync(IServiceProvider serviceProvider)
{
switch (serviceProvider)
{
case IAsyncDisposable asyncDisposable:
await asyncDisposable.DisposeAsync();
break;
case IDisposable disposable:
disposable.Dispose();
break;
}
}
}
WebHost初始化时,先验证IStartup接口是否已经注册了
接下来看下StartAsync方法
首先调用BuildApplication创建RequestDelegate
RequestDelegate是一个委托delegate Task RequestDelegate(HttpContext context),用于处理请求
该方法主要构建处理请求的委托链,看下如何具体实现的
这里涉及到两个关键接口IApplicationBuilder、IApplicationBuilderFactory
IApplicationBuilder的实现类
public class ApplicationBuilder : IApplicationBuilder
{
private const string ServerFeaturesKey = "server.Features";
private const string ApplicationServicesKey = "application.Services";
private readonly IList> _components = new List>();
public ApplicationBuilder(IServiceProvider serviceProvider)
{
Properties = new Dictionarystring, object>(StringComparer.Ordinal);
ApplicationServices = serviceProvider;
}
public ApplicationBuilder(IServiceProvider serviceProvider, object server)
: this(serviceProvider)
{
SetProperty(ServerFeaturesKey, server);
}
private ApplicationBuilder(ApplicationBuilder builder)
{
Properties = new CopyOnWriteDictionarystring, object>(builder.Properties, StringComparer.Ordinal);
}
public IServiceProvider ApplicationServices
{
get
{
return GetProperty(ApplicationServicesKey);
}
set
{
SetProperty(ApplicationServicesKey, value);
}
}
public IFeatureCollection ServerFeatures
{
get
{
return GetProperty(ServerFeaturesKey);
}
}
public IDictionarystring, object> Properties { get; }
private T GetProperty(string key)
{
object value;
return Properties.TryGetValue(key, out value) ? (T)value : default(T);
}
private void SetProperty(string key, T value)
{
Properties[key] = value;
}
public IApplicationBuilder Use(Func middleware)
{
_components.Add(middleware);
return this;
}
public IApplicationBuilder New()
{
return new ApplicationBuilder(this);
}
public RequestDelegate Build()
{
RequestDelegate app = context =>
{
// If we reach the end of the pipeline, but we have an endpoint, then something unexpected has happened.
// This could happen if user code sets an endpoint, but they forgot to add the UseEndpoint middleware.
var endpoint = context.GetEndpoint();
var endpointRequestDelegate = endpoint?.RequestDelegate;
if (endpointRequestDelegate != null)
{
var message =
$"The request reached the end of the pipeline without executing the endpoint: ‘{endpoint.DisplayName}‘. " +
$"Please register the EndpointMiddleware using ‘{nameof(IApplicationBuilder)}.UseEndpoints(...)‘ if using " +
$"routing.";
throw new InvalidOperationException(message);
}
context.Response.StatusCode = 404;
return Task.CompletedTask;
};
foreach (var component in _components.Reverse())
{
app = component(app);
}
return app;
}
}
字段_components保存一个委托列表,当调用Use方法时,添加委托到字段中
最后调用Build方法创建RequestDelegate
public class ApplicationBuilderFactory : IApplicationBuilderFactory
{
private readonly IServiceProvider _serviceProvider;
public ApplicationBuilderFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IApplicationBuilder CreateBuilder(IFeatureCollection serverFeatures)
{
return new ApplicationBuilder(_serviceProvider, serverFeatures);
}
}
ApplicationBuilderFactory用于创建ApplicationBuilder
我们再回到BuildApplication中
应用找到所有实现IStartupFilter的类型,再结合IStartup类型的Configure方法构建委托链,再构建RequestDelegate
构建好RequestDelegate后,再调用HostedServiceExecutor来执行IHostedService
internal class HostedServiceExecutor
{
private readonly IEnumerable _services;
private readonly ILogger _logger;
public HostedServiceExecutor(ILogger logger, IEnumerable services)
{
_logger = logger;
_services = services;
}
public Task StartAsync(CancellationToken token)
{
return ExecuteAsync(service => service.StartAsync(token));
}
public Task StopAsync(CancellationToken token)
{
return ExecuteAsync(service => service.StopAsync(token), throwOnFirstFailure: false);
}
private async Task ExecuteAsync(Func callback, bool throwOnFirstFailure = true)
{
List exceptions = null;
foreach (var service in _services)
{
try
{
await callback(service);
}
catch (Exception ex)
{
if (throwOnFirstFailure)
{
throw;
}
if (exceptions == null)
{
exceptions = new List();
}
exceptions.Add(ex);
}
}
// Throw an aggregate exception if there were any exceptions
if (exceptions != null)
{
throw new AggregateException(exceptions);
}
}
}
接下来看下IHttpContextFactory怎么创建HttpContext的
IHttpContextFactory接口的默认实现DefaultHttpContextFactory
public class DefaultHttpContextFactory : IHttpContextFactory
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly FormOptions _formOptions;
private readonly IServiceScopeFactory _serviceScopeFactory;
// This takes the IServiceProvider because it needs to support an ever expanding
// set of services that flow down into HttpContext features
public DefaultHttpContextFactory(IServiceProvider serviceProvider)
{
// May be null
_httpContextAccessor = serviceProvider.GetService();
_formOptions = serviceProvider.GetRequiredService>().Value;
_serviceScopeFactory = serviceProvider.GetRequiredService();
}
public HttpContext Create(IFeatureCollection featureCollection)
{
if (featureCollection is null)
{
throw new ArgumentNullException(nameof(featureCollection));
}
var httpContext = new DefaultHttpContext(featureCollection);
Initialize(httpContext);
return httpContext;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void Initialize(DefaultHttpContext httpContext, IFeatureCollection featureCollection)
{
Debug.Assert(featureCollection != null);
Debug.Assert(httpContext != null);
httpContext.Initialize(featureCollection);
Initialize(httpContext);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private DefaultHttpContext Initialize(DefaultHttpContext httpContext)
{
if (_httpContextAccessor != null)
{
_httpContextAccessor.HttpContext = httpContext;
}
httpContext.FormOptions = _formOptions;
httpContext.ServiceScopeFactory = _serviceScopeFactory;
return httpContext;
}
public void Dispose(HttpContext httpContext)
{
if (_httpContextAccessor != null)
{
_httpContextAccessor.HttpContext = null;
}
}
internal void Dispose(DefaultHttpContext httpContext)
{
if (_httpContextAccessor != null)
{
_httpContextAccessor.HttpContext = null;
}
httpContext.Uninitialize();
}
}
再来看下IHttpApplication接口
实现类HostingApplication:
internal class HostingApplication : IHttpApplication
{
private readonly RequestDelegate _application;
private readonly IHttpContextFactory _httpContextFactory;
private readonly DefaultHttpContextFactory _defaultHttpContextFactory;
private HostingApplicationDiagnostics _diagnostics;
public HostingApplication(
RequestDelegate application,
ILogger logger,
DiagnosticListener diagnosticSource,
IHttpContextFactory httpContextFactory)
{
_application = application;
_diagnostics = new HostingApplicationDiagnostics(logger, diagnosticSource);
if (httpContextFactory is DefaultHttpContextFactory factory)
{
_defaultHttpContextFactory = factory;
}
else
{
_httpContextFactory = httpContextFactory;
}
}
// Set up the request
public Context CreateContext(IFeatureCollection contextFeatures)
{
Context hostContext;
if (contextFeatures is IHostContextContainer container)
{
hostContext = container.HostContext;
if (hostContext is null)
{
hostContext = new Context();
container.HostContext = hostContext;
}
}
else
{
// Server doesn‘t support pooling, so create a new Context
hostContext = new Context();
}
HttpContext httpContext;
if (_defaultHttpContextFactory != null)
{
var defaultHttpContext = (DefaultHttpContext)hostContext.HttpContext;
if (defaultHttpContext is null)
{
httpContext = _defaultHttpContextFactory.Create(contextFeatures);
hostContext.HttpContext = httpContext;
}
else
{
_defaultHttpContextFactory.Initialize(defaultHttpContext, contextFeatures);
httpContext = defaultHttpContext;
}
}
else
{
httpContext = _httpContextFactory.Create(contextFeatures);
hostContext.HttpContext = httpContext;
}
_diagnostics.BeginRequest(httpContext, hostContext);
return hostContext;
}
// Execute the request
public Task ProcessRequestAsync(Context context)
{
return _application(context.HttpContext);
}
// Clean up the request
public void DisposeContext(Context context, Exception exception)
{
var httpContext = context.HttpContext;
_diagnostics.RequestEnd(httpContext, exception, context);
if (_defaultHttpContextFactory != null)
{
_defaultHttpContextFactory.Dispose((DefaultHttpContext)httpContext);
}
else
{
_httpContextFactory.Dispose(httpContext);
}
_diagnostics.ContextDisposed(context);
// Reset the context as it may be pooled
context.Reset();
}
internal class Context
{
public HttpContext HttpContext { get; set; }
public IDisposable Scope { get; set; }
public Activity Activity { get; set; }
public long StartTimestamp { get; set; }
internal bool HasDiagnosticListener { get; set; }
public bool EventLogEnabled { get; set; }
public void Reset()
{
// Not resetting HttpContext here as we pool it on the Context
Scope = null;
Activity = null;
StartTimestamp = 0;
HasDiagnosticListener = false;
EventLogEnabled = false;
}
}
}
其中内部类Context对请求进行了封装
介绍上面的两个类型,主要是IServer的StartAsync方法调用到
var diagnosticSource = _applicationServices.GetRequiredService();
var httpContextFactory = _applicationServices.GetRequiredService();
var hostingApp = new HostingApplication(application, _logger, diagnosticSource, httpContextFactory);
await Server.StartAsync(hostingApp, cancellationToken).ConfigureAwait(false);
_startedServer = true;
// Fire IApplicationLifetime.Started
_applicationLifetime?.NotifyStarted();
这时候进入到了IServer处理请求的环节了
以上主要介绍了IWebHost的运行原理。
asp.net core 3.1 源码学习(二)
标签:listener configure spro with miss token 初始 VID opp
原文地址:https://www.cnblogs.com/lanpingwang/p/12564189.html