如果您曾经使用过 ASP.NET Core,那么您可能会熟悉 Startup 类。按照惯例,此类至少包含一个名为 Configure 的方法。通常,还包含一个 ConfigureServices 方法,用于向 Microsoft 依赖注入容器注册服务,但这不是绝对要求。
configure 方法是您通过注册框架或自定义中间件组件来定义应用程序的请求处理管道的地方。
你有没有想过你在 Startup 类的 Configure 方法中包含的代码是如何转换为管道来处理请求的?别再想了!在这篇文章中,我们将探索一些 ASP.NET Core 源代码并回答这个问题。
这篇文章深入探讨了 ASP.NET Core 的一些实现细节。这不是有效使用 ASP.NET Core 的必读内容,它是中间件管道。但是,我相信了解这些细节对于了解应用程序内部正在发生的事情是有价值的。我将在这篇文章中展示一些看起来相当复杂的代码片段,并尽我所能解释它们。如果您一开始不了解所有内容,请不要担心。
我们将使用一个简单的应用程序来演示我们可以放入单个文件中的流程。
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Hosting;
namespace BasicWebSite
{
public class Program
{
public static void Main(string[] args) => CreateHostBuilder(args).Build().Run();
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
webBuilder.UseStartup<Startup>());
}
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Use(async (context, next) =>
{
if (context.Request.Path == "/")
{
await context.Response.WriteAsync("Hello World!");
return;
}
await next();
});
}
}
}
在 Program 类中,main 方法构建并运行一个主机。主机概念支持长时间运行的 .NET Core 应用程序,提供依赖注入和配置等功能。
要创建主机,使用静态 CreateHostBuilder 方法。这首先使用 Host.CreateDefaultBuilder 方法建立一个通用主机构建器。还调用了 ConfigureWebHostDefaults,以启用对托管 ASP.NET Core 应用程序的支持。此方法接受一个 Action<IWebHostBuilder> 可用于进一步配置 Web 主机并使 ASP.NET Core 能够正常工作。
在此示例中,表达式 lambda 用于通过调用 UseStartup 将 Web 主机指向 Startup 类。按照惯例,Startup 类用于配置服务和请求管道。
此示例的 Startup 类包含一个单独的 Configure 方法。此方法接受 IApplicationBuilder 参数。IApplicationBuilder 可用于为此 ASP.NET Core 应用程序配置请求处理管道。
/// <summary>
/// A function that can process an HTTP request.
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> for the request.</param>
/// <returns>A task that represents the completion of request processing.</returns>
public delegate Task RequestDelegate(HttpContext context);
对于一些 .NET 开发人员来说,delegate 关键字可能是一个新概念,因为用户代码并不经常需要它。Microsoft 文档定义了一个委托, 如下所示……
“委托是一种类型,它表示对具有特定参数列表和返回类型的方法的引用。”
您可能认为这听起来与 Action<T> 或 Func<T> 非常相似,您是对的。这两种类型实际上都是委托,并使用委托关键字定义。对于一般用途,Func 和 Action 很容易应用。在某些情况下,正如我们在 RequestDelegate 中所遇到的那样,想要提供更多含义,可以定义一个特定的委托签名。
RequestDelegate 类型代表任何 Task 返回方法,它有一个 HttpContext 类型的参数。因此,RequestDelegate 可以对 HttpContext 进行异步操作。
ASP.NET Core 请求处理是通过将一个或多个 RequestDelegate 实例链接在一起来实现的。每个委托都可以通过写入 HttpContext 上的响应来处理请求。如果 RequestDelegate 被认为是终端,即它已经完全完成了响应,它可以简单地返回。在没有完全处理请求的情况下,它可能会将 HttpContext 传递给链中的下一个 RequestDelegate。
在更高的层次上,我们经常将其视为一系列中间件组件。定义中间件类时,主要要求之一是它包含一个名为 Invoke 或 InvokeAsync 的方法。两者都适合,尽管从 ASP.NET Core 2.0 开始,后者更常用。
该方法的签名如下……
public Task InvokeAsync(HttpContext httpContext)
如果您关注签名,您将看到它与 RequestDelegate 的签名相匹配。它接受一个 HttpContext 并返回一个任务。
中间件类是用于提供请求处理功能的常见概念。如果您构建了任何 ASP.NET Core 应用程序,那么您就已经使用了中间件,无论是否有意。对于应用程序中常见的横切关注点,编写自己的中间件是一项相对简单的练习。
对于这篇文章,我想重点关注我们如何从 Configure 方法到最终的请求处理管道。我们将忽略中间件类的概念,而是通过注册一个内联中间件组件来定义我们的请求管道。
https://www.stevejgordon.co.uk/how-is-the-asp-net-core-middleware-pipeline-built
本文链接:https://blog.nnwk.net/article/60
有问题请留言。版权所有,转载请在显眼位置处保留文章出处,并留下原文连接
Leave your question and I'll get back to you as soon as I see it. All rights reserved. Please keep the source and links
友情链接:
子卿全栈
全部评论