65.9K
CodeProject 正在变化。 阅读更多。
Home

将 HTTP 处理程序和 HTTP 模块迁移到 ASP.NET Core 中间件的基本步骤。

2016年12月6日

CPOL

6分钟阅读

viewsIcon

32562

迁移 HTTP 处理程序和 HTTP 模块到 ASP.NET Core 中间件

引言

我的团队正在将 Angular JS 1.5.XX 和 MVC 5 迁移到使用 Angular 2.0 的 .NET Core Web App。在迁移过程中,我们意识到项目中使用了 HTTP 处理程序。我们决定也迁移它们,尽管这是一个大胆的决定 ;-)。在迁移过程中,我们遇到了一些挑战,但最终成功迁移了。然后我决定写一篇文章,对迁移过程进行一个高层次的介绍。这篇文章就是这样诞生的 :-)。

本文提供了在将 HTTP 处理程序和模块迁移到 ASP.NET Core 中间件时需要遵循的基本步骤。本文不会深入探讨 HTTP 处理程序和模块,也不会深入探讨 ASP.NET Core 中间件。我只会使用 Response 对象在 Web 浏览器中显示输出。我希望这篇文章保持非常简单。在实际场景中,处理程序和模块涉及应用程序的关键逻辑。我的目的是通过代码示例提供 HTTP 处理程序和模块以及 ASP.NET Core 中间件的高层次介绍,因为我认为这将有助于初步理解 ASP.NET Core 中间件。

在本文中,我使用了 VS 2015 Update 3。

我为本文规划了以下内容:

  1. HTTP 处理程序
  2. HTTP 模块
  3. 创建一个带有示例 HTTP 处理程序和模块的 VS 项目
  4. ASP.NET 中间件及其关键方法
  5. 创建一个带有示例 ASP.NET Core 中间件的 VS 项目
  6. 将步骤 #3 中创建的 HTTP 处理程序和模块迁移到 ASP.NET 中间件
  7. HTTP 处理程序和模块与 ASP.NET Core 中间件之间的主要区别

1. HTTP 处理程序

HTTP 处理程序会在 Web 服务器收到的每个请求的响应中运行。最常见的例子是 *.aspx* 或 *.rss* 提要。可以根据自己的需求创建 HTTP 处理程序,并将输出渲染到 Web 浏览器。它们是通过实现 `IHttpHandler` 的 `ProcessRequest()` 来创建的。

public class CustomReportHandler : IHttpHandler
    {
        #region IHttpHandler Members 
        public bool IsReusable
        {
            get { return false; }
        } 
        public void ProcessRequest(HttpContext context)
        {
            var response = context.Response; 
            response.Write
            ("<h2>This handler is written for processing files with .report extension<h2>");
           
          //more logic follows...
        } 
        #endregion
    }

2. HTTP 模块

HTTP 模块是为应用程序收到的每个请求调用的类。它们可以访问 HTTP 管道的生命周期事件。可以通过实现 `IHttpModule` 的 `Init()` 来创建自定义的 HTTP 模块。

public class CustomModule : IHttpModule
    {
        #region IHttpModule Members 
        public void Dispose()
        {
            //clean-up code here.
        }

        public void Init(HttpApplication context)
        {
            context.BeginRequest += (source, arguments) =>
            {
                var httpApplication = (HttpApplication)source;
                var httpContext = httpApplication.Context; 
                httpContext.Response.Write("<h3>Custom module started the begin request</h3>");
               
               // More logic goes here.... 
              //httpApplication.CompleteRequest();// if you want to short-circut the request,
                                                  // then call the CompleteRequest().
            }; 
           
          context.EndRequest += (source, arguments) =>
            {
                var httpApplication = (HttpApplication)source;
                var httpContext = httpApplication.Context; 
                httpContext.Response.Write("<h3>Custom module completed the request</h3>"); 
               
               // More logic goes here....
            };
        } 
        #endregion

3. 创建一个带有示例 HTTP 处理程序和模块的 VS 项目

  • 打开 VS 2015,创建一个名为 "MigratingHttpHandlersModulesToMiddleware" 的空白解决方案。您可以随意命名。
  • 添加一个名为 "CustomHandlersModules" 的新项目(ASP.NET Web 应用程序),并选择 "Empty" 模板。
  • 创建一个名为 "CustomReportHandler" 的类,并实现 `IHttpHandler`。您可以从上面的 HTTP 处理程序部分复制代码片段。
    • 使用以下条目更新 `Web.config` 文件:
      <!--Under configuration - system.webServer - handlers section add below:-->
      <add name="CustomReportHandler" verb="*" path="*.report" 
      type="CustomHandlersModules.CustomReportHandler" resourceType="Unspecified"/> 
    • 此处理程序将在 Web 应用程序收到以 `.report` 扩展名结尾的资源请求时运行。
    • 按 Ctrl + F5,访问 `https://:29342/test.report`。您的端口可能不同。
    • 您将在 Web 浏览器中看到输出:This handler is written for processing files with .report extension
  • 创建一个名为 "CustomModule" 的类,并实现 `IHttpModule`。您可以从上面的 HTTP 模块部分复制代码片段。
    • 使用以下条目更新 `Web.config` 文件:
      <!--Under configuration - system.webServer - modules section add below:-->
      <add name="CustomModule" type="CustomHandlersModules.CustomModule"/>
    • 按 Ctrl + F5,访问 `https://:29342/test.report`。您的端口可能不同。
    • 您将在 Web 浏览器中看到以下输出:
      Custom module started the begin request.
      This handler is written for processing files with .report extension.
      Custom module completed the request.

在 Web 浏览器中。

4. ASP.NET 中间件及其关键方法

到目前为止,我们看到的是我们都习惯于实现的 Handler 和 Module 的实现。现在,我们将进入 ASP.Core 的有趣主题——中间件。

什么是中间件?它们是添加到应用程序管道中的代码。代码会应用一些逻辑,并在管道中处理请求。

为了实现这一点,我们可以使用传递给 Request Delegate 的 Application Builder 的 4 个方法:

  • Run:这将终止 http 管道。
  • Use:将中间件添加到请求管道。
  • Map:这用于根据请求的路径匹配请求委托。
  • MapWhen:此方法支持基于谓词的中间件分支,允许独立的管道。

创建核心应用程序时,入口点是 `Startup.cs`。此类有两个方法:`Configure()` 和 `ConfigureServices()`。`Configure()` 是定义和执行所有中间件的地方。`ConfigureServices()` 是应用程序使用的所有服务的存放处。

您可以在 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware 找到更多相关文档。

现在我们有了基本了解,让我们开始创建 ASP.NET Core 应用程序。

5. 创建一个带有示例 ASP.NET Core 中间件的 VS 项目

  • 打开 VS 2015 解决方案,添加一个名为 "CustomMiddlewareForHttpHandlersModules" 的新项目,模板为 ASP.NET Core Web Application (.NET Core),并选择 Blank 模板。
  • 在 `Startup.cs` 中,在 `app.Run()` 之前添加以下内容:
     app.Use(async (context, next) => {
    
                    await context.Response.WriteAsync("Custom call!!!!! <br/>");
                    await next.Invoke();
                });
  • 按 Ctrl + F5。您将在 Web 浏览器中看到上述输出以及 "Hello World!"。

既然我们已经了解了基本中间件,让我们开始迁移 Handler,然后再迁移 Module。

6. 将步骤 #3 中创建的 HTTP 处理程序和模块迁移到 ASP.NET 中间件

6a. 迁移 HTTP 处理程序

在本节中,我们将迁移在步骤 #3 中创建的处理程序。

  • 添加一个名为 "CustomHanlderMiddleware" 的类,并在其中包含以下代码:
    public class CustomHanlderMiddleware
        {
            private RequestDelegate _next;
    
            public CustomHanlderMiddleware(RequestDelegate next)
            {
                _next = next;
            }
    
            public async Task Invoke(HttpContext context)
            {
                await context.Response.WriteAsync
                ("<h2>This handler is written for processing files with .report extension<h2>");
    
                //more logic follows...
            }
        }
  • 为了在请求管道中使用上面创建的 `CustomHandlerMiddleware`,我们需要创建一个 `ApplicationBuilder` 的扩展方法。创建一个名为 "CustomMiddlewareExtensions" 的类,并按如下方式放置代码:
    public static class CustomMiddlewareExtensions
        {
            public static IApplicationBuilder UseCustomHanlderMiddleware
                                          (this IApplicationBuilder builder)
            {
                return builder.UseMiddleware<CustomHanlderMiddleware>();
            }
        }
  • 在 `Startup.cs` 中,将以下代码放在 `app.Run()` 的正上方。
               app.Use(async (context, next) => {
    
                    await context.Response.WriteAsync("Custom call!!!!! <br/>");
                    await next.Invoke();
                });
    
                // For Handler
                app.MapWhen(context => context.Request.Path.ToString().EndsWith(".report"),
                    appBuilder => {
                        appBuilder.UseCustomHanlderMiddleware();
                    });
    
                app.Run(async (context) =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
  • `next.Invoke()` 方法用于调用管道中的下一个请求委托。通过不调用 `next` 可以终止调用。

6b. 迁移 HTTP 模块

在本节中,我们将迁移在步骤 #3 中创建的模块。

  • 添加一个名为 "CustomModuleMiddleware" 的类。并在其中包含以下代码:
    public class CustomModuleMiddleware
        {
            private RequestDelegate _next;
            public CustomModuleMiddleware(RequestDelegate next)
            {
                _next = next;
            }
            public async Task Invoke(HttpContext context)
            {
                await context.Response.WriteAsync("<h3>Custom module started the begin request</h3>");
    
                await _next.Invoke(context);
    
                await context.Response.WriteAsync("<h3>Custom module completed the request</h3>");
            }
        }
  • 在 `CustomerMiddlewareExtensions.cs` 中,创建一个将中间件添加到请求管道的扩展方法。该类应如下所示:
    public static class CustomMiddlewareExtensions
        {
            public static IApplicationBuilder UseCustomHanlderMiddleware
                                      (this IApplicationBuilder builder)
            {
                return builder.UseMiddleware<CustomHanlderMiddleware>();
            }
            public static IApplicationBuilder UseCustomModuleMiddleware
                                      (this IApplicationBuilder builder)
            {
                return builder.UseMiddleware<CustomModuleMiddleware>();
            }
        }
  • 在 `Startup.cs` 中,将以下代码放在 `app.Run()` 的正上方。
               app.Use(async (context, next) => {
    
                    await context.Response.WriteAsync("Custom call!!!!! <br/>");
                    await next.Invoke();
                });
    
                // For Module
                app.UseCustomModuleMiddleware();
    
                // For Handler
                app.MapWhen(context => context.Request.Path.ToString().EndsWith(".report"),
                    appBuilder => {
                        appBuilder.UseCustomHanlderMiddleware();
                    });
    
                app.Run(async (context) =>
                {
                    await context.Response.WriteAsync("Hello World!");
                });
  • 按 Ctrl + F5。访问 `https://:31736/test.report`。

最后,我们将 Handler 和 Module 迁移到了 ASP.NET Core 中间件。要查看相同输出,您可以注释掉 `app.Use()` 和 `app.Run()`。

7. HTTP 处理程序和模块与 ASP.NET Core 中间件之间的主要区别

  • Web.config
    • 对于 Handler 和 Modules:我们需要修改
    • 对于 ASP.NET Core:无需修改
  • 应用程序生命周期
    • 对于 Handler 和 Modules:我们有它
    • 对于 ASP.NET Core:它不存在
  • 请求管道终止
    • 对于 Handler 和 Modules:`CompleteRequest()` 会终止请求
    • 对于 ASP.NET Core:通过不将请求委托传递给下一个组件

关注点

  • 我们认为 ASP.NET Core 中间件是 HTTP 处理程序和模块的组合。
  • 在 `Startup.cs` 的 `configure()` 方法中放置 `app.Use()` 方法是中间件执行的关键。
  • ASP.NET Core 提供了多种开箱即用的中间件。例如:身份验证、会话、CORS 等。

结束语

我已将包含不同中间件(主要是内存中的会话)和数据传递的代码放在 GitHub 上。代码可在 https://github.com/psdinesh/MigratingHttpHandlersModulesAspNetCoreMiddleware 找到。

© . All rights reserved.