NetCore解读请求处理管道

时间:2021-10-09
本文章向大家介绍NetCore解读请求处理管道,主要包括NetCore解读请求处理管道使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

一、请求处理管道

前面分别介绍了服务器、中间件管道、托管服务和主机,那么请求管道具体是怎样的,它们之间有什么关系?正常来说,ASP.NET Core的请求处理管道由一个服务器和中间件管道构成。但对于面向传输层的服务器来说,它其实没有中间件的概念。不管服务器类型,当服务器接收到请求之后,会将该请求分发给一个处理器进行处理,对服务器而言,这个处理器就是一个HTTP应用,此应用通过IHttpApplication<TContext>接口来表示,如下是IHttpApplication<TContext> 的定义: 
/// <summary>
/// Represents an application.
/// </summary>
/// <typeparam name="TContext">The context associated with the application.</typeparam>
public interface IHttpApplication<TContext> where TContext : notnull
{
    /// <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);
}

由于服务器是通过IServer接口表示的,所以可以将ASP.NET Core框架的核心视为由IServer和IHttpApplication<TContext>对象组成的管道,即请求处理管道。

我们可以根据需要注册不同类型的服务器,在默认情况下,IHttpApplication由HostingApplication实现,如下面源码所示:
 internal class HostingApplication : IHttpApplication<HostingApplication.Context>

HostingApplication对象由指定的RequestDelegate对象来完成所有的请求处理工作,如下面源码所示:

internal class HostingApplication : IHttpApplication<HostingApplication.Context>
    {
        private readonly RequestDelegate _application;
        private readonly IHttpContextFactory? _httpContextFactory;
        private readonly DefaultHttpContextFactory? _defaultHttpContextFactory;
        private readonly HostingApplicationDiagnostics _diagnostics;

        public HostingApplication(
            RequestDelegate application,
            ILogger logger,
            DiagnosticListener diagnosticSource,
            ActivitySource activitySource,
            DistributedContextPropagator propagator,
            IHttpContextFactory httpContextFactory)
        {
            _application = application;
            _diagnostics = new HostingApplicationDiagnostics(logger, diagnosticSource, activitySource, propagator);
            if (httpContextFactory is DefaultHttpContextFactory factory)
            {
                _defaultHttpContextFactory = factory;
            }
            else
            {
                _httpContextFactory = httpContextFactory;
            }
        }
..........
// Execute the request public Task ProcessRequestAsync(Context context) { return _application(context.HttpContext!); }
     ............
}

而RequestDelegate就是中间件委托链,所有的这一切都被GenericWebHostService整合在一起。如下是GenericWebHostService类的StartAsync方法:

public async Task StartAsync(CancellationToken cancellationToken)
{
    HostingEventSource.Log.HostStart();

    var serverAddressesFeature = Server.Features.Get<IServerAddressesFeature>();
    var addresses = serverAddressesFeature?.Addresses;
    if (addresses != null && !addresses.IsReadOnly && addresses.Count == 0)
    {
        var urls = Configuration[WebHostDefaults.ServerUrlsKey];
        if (!string.IsNullOrEmpty(urls))
        {
            serverAddressesFeature!.PreferHostingUrls = WebHostUtilities.ParseBool(Configuration, WebHostDefaults.PreferHostingUrlsKey);

            foreach (var value in urls.Split(';', StringSplitOptions.RemoveEmptyEntries))
            {
                addresses.Add(value);
            }
        }
    }
    //中间件委托链
    RequestDelegate? application = null;

    try
    {
        var configure = Options.ConfigureApplication;

        if (configure == null)
        {
            throw new InvalidOperationException($"No application configured. Please specify an application via IWebHostBuilder.UseStartup, IWebHostBuilder.Configure, or specifying the startup assembly via {nameof(WebHostDefaults.StartupAssemblyKey)} in the web host configuration.");
        }

        var builder = ApplicationBuilderFactory.CreateBuilder(Server.Features);

        foreach (var filter in StartupFilters.Reverse())
        {
            configure = filter.Configure(configure);
        }

        configure(builder);

        // Build the request pipeline
        application = builder.Build();
    }
    catch (Exception ex)
    {
        Logger.ApplicationError(ex);

        if (!Options.WebHostOptions.CaptureStartupErrors)
        {
            throw;
        }
     
        var showDetailedErrors = HostingEnvironment.IsDevelopment() || Options.WebHostOptions.DetailedErrors;

        application = ErrorPageBuilder.BuildErrorPageApplication(HostingEnvironment.ContentRootFileProvider, Logger, showDetailedErrors, ex);
    }
    //创建HostingApplication对象,关联中间件委托链
    var httpApplication = new HostingApplication(application, Logger, DiagnosticListener, ActivitySource, Propagator, HttpContextFactory);

    await Server.StartAsync(httpApplication, cancellationToken);

    if (addresses != null)
    {
        foreach (var address in addresses)
        {
            Log.ListeningOnAddress(LifetimeLogger, address);
        }
    }

    if (Logger.IsEnabled(LogLevel.Debug))
    {
        foreach (var assembly in Options.WebHostOptions.GetFinalHostingStartupAssemblies())
        {
            Log.StartupAssemblyLoaded(Logger, assembly);
        }
    }

    if (Options.HostingStartupExceptions != null)
    {
        foreach (var exception in Options.HostingStartupExceptions.InnerExceptions)
        {
            Logger.HostingStartupAssemblyError(exception);
        }
    }
}

二、请求管道简略图

 

三、请求管道流程图

原文地址:https://www.cnblogs.com/qtiger/p/15386971.html