一、IApplicationBuilderFactory
public interface IApplicationBuilderFactory { IApplicationBuilder CreateBuilder(IFeatureCollection serverFeatures); }
public class ApplicationBuilderFactory : IApplicationBuilderFactory { private readonly IServiceProvider _serviceProvider; public ApplicationBuilderFactory(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; } public IApplicationBuilder CreateBuilder(IFeatureCollection serverFeatures) { return new ApplicationBuilder(_serviceProvider, serverFeatures); } }
二、 IApplicationBuilder
public interface IApplicationBuilder { /// <summary> /// Gets or sets the <see cref="IServiceProvider"/> that provides access to the application's service container. /// </summary> IServiceProvider ApplicationServices { get; set; } /// <summary> /// Gets the set of HTTP features the application's server provides. /// </summary> IFeatureCollection ServerFeatures { get; } /// <summary> /// Gets a key/value collection that can be used to share data between middleware. /// </summary> IDictionary<string, object> Properties { get; } /// <summary> /// Adds a middleware delegate to the application's request pipeline. /// </summary> /// <param name="middleware">The middleware delegate.</param> /// <returns>The <see cref="IApplicationBuilder"/>.</returns> IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware); /// <summary> /// Creates a new <see cref="IApplicationBuilder"/> that shares the <see cref="Properties"/> of this /// <see cref="IApplicationBuilder"/>. /// </summary> /// <returns>The new <see cref="IApplicationBuilder"/>.</returns> IApplicationBuilder New(); /// <summary> /// Builds the delegate used by this application to process HTTP requests. /// </summary> /// <returns>The request handling delegate.</returns> RequestDelegate Build(); }
public class ApplicationBuilder : IApplicationBuilder { private const string ServerFeaturesKey = "server.Features"; private const string ApplicationServicesKey = "application.Services"; private readonly IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>(); public ApplicationBuilder(IServiceProvider serviceProvider) { Properties = new Dictionary<string, object>(StringComparer.Ordinal); ApplicationServices = serviceProvider; } public ApplicationBuilder(IServiceProvider serviceProvider, object server) : this(serviceProvider) { SetProperty(ServerFeaturesKey, server); } private ApplicationBuilder(ApplicationBuilder builder) { Properties = new CopyOnWriteDictionary<string, object>(builder.Properties, StringComparer.Ordinal); } public IServiceProvider ApplicationServices { get { return GetProperty<IServiceProvider>(ApplicationServicesKey); } set { SetProperty<IServiceProvider>(ApplicationServicesKey, value); } } public IFeatureCollection ServerFeatures { get { return GetProperty<IFeatureCollection>(ServerFeaturesKey); } } public IDictionary<string, object> Properties { get; } private T GetProperty<T>(string key) { object value; return Properties.TryGetValue(key, out value) ? (T)value : default(T); } private void SetProperty<T>(string key, T value) { Properties[key] = value; } public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> 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; } }
ApplicationBuilder中的字段_components保存asp.netcore的处理管道,当我们调用Use(Func<RequestDelegate, RequestDelegate> middleware)方法时,就把管道注册到列表中
Build()方法构建出RequestDelegate,这个委托链是asp.netcore管道处理请求和响应的核心
三、IHttpContextFactory
public interface IHttpContextFactory { HttpContext Create(IFeatureCollection featureCollection); void Dispose(HttpContext httpContext); }
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<IHttpContextAccessor>(); _formOptions = serviceProvider.GetRequiredService<IOptions<FormOptions>>().Value; _serviceScopeFactory = serviceProvider.GetRequiredService<IServiceScopeFactory>(); } 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
/// <summary> /// Represents an application. /// </summary> /// <typeparam name="TContext">The context associated with the application.</typeparam> public interface IHttpApplication<TContext> { /// <summary> /// Create a TContext given a collection of HTTP features. /// </summary> /// <param name="contextFeatures">A collection of HTTP features to be used for creating the TContext.</param> /// <returns>The created TContext.</returns> TContext CreateContext(IFeatureCollection contextFeatures); /// <summary> /// Asynchronously processes an TContext. /// </summary> /// <param name="context">The TContext that the operation will process.</param> Task ProcessRequestAsync(TContext context); /// <summary> /// Dispose a given TContext. /// </summary> /// <param name="context">The TContext to be disposed.</param> /// <param name="exception">The Exception thrown when processing did not complete successfully, otherwise null.</param> void DisposeContext(TContext context, Exception exception); }
internal class HostingApplication : IHttpApplication<HostingApplication.Context> { 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<Context> 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; } } }
IHttpApplication可以看成是一个请求
CreateContext创建Context对象
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; } }
ProcessRequestAsync方法最终调用上面的RequestDelegate,进入到asp.netcore的管道中处理请求和响应