dotnet core 中间件

## 官方说明

中间件是一种装配到应用管道以处理请求和响应的软件。 每个组件:

  • 选择是否将请求传递到管道中的下一个组件。
  • 可在管道中的下一个组件前后执行工作。

请求委托用于生成请求管道。 请求委托处理每个 HTTP 请求。

使用 RunMap 和 Use 扩展方法来配置请求委托。 可将一个单独的请求委托并行指定为匿名方法(称为并行中间件),或在可重用的类中对其进行定义。 这些可重用的类和并行匿名方法即为中间件 ,也叫中间件组件 。 请求管道中的每个中间件组件负责调用管道中的下一个组件,或使管道短路。 当中间件短路时,它被称为“终端中间件” ,因为它阻止中间件进一步处理请求。

## 执行顺序示例图

## 实测一下

++新建dotnet core 3.1 web 项目++
在 ==Startup== 的 ==Configure== 中

  public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.Use(async (context, next) =>
            {
                Stopwatch stopWatch = new Stopwatch();
                stopWatch.Start();
                await context.Response.WriteAsync("Middleware 1 Start \n");
                await next.Invoke();
                await context.Response.WriteAsync("Middleware 1 End \n");
                stopWatch.Stop();
                Console.WriteLine($"响应:{stopWatch.ElapsedMilliseconds}");
            });

            app.Use(async (context, next) =>
            {

                await context.Response.WriteAsync("Middleware 2 Start \n");

                await next.Invoke();

                await context.Response.WriteAsync("Middleware 2 End \n");

            });

            app.Use(async (context, next) =>
            {

                await context.Response.WriteAsync("Middleware 2 Start \n");

                await next.Invoke();

                await context.Response.WriteAsync("Middleware 2 End \n");

            });

            app.UseRouting();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    await context.Response.WriteAsync("Hello World! \n");
                });

                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });

            app.Use(async (context, next) =>
            {

                await context.Response.WriteAsync("Middleware Use Last Start");

                await next.Invoke();

                await context.Response.WriteAsync("Middleware Use Last End");

            });

        }
    }
运行结果

可以看到按照顺序执行了 Middleware 1 Middleware 2 ,最后一个注册的中间件没有被执行,因为mvc中,如果请求与路由匹配,则为终端,短路了最后一个中间件的处理。

使用Run可以注册终端中间件,加入到 Middleware 2 下面

app.Run(async (context) =>
{
    await context.Response.WriteAsync("Middleware 3 \n");
});
运行结果

自定义


  1. 自定义类
  public class MyMiddleware1
    {

        private readonly RequestDelegate _next;
        public MyMiddleware1(RequestDelegate next)
        {
            _next = next;
        }
        public async Task InvokeAsync(HttpContext context)
        {
            await context.Response.WriteAsync("MyMiddleware1 Start \n");

            await _next.Invoke(context);

            await context.Response.WriteAsync("MyMiddleware1 End \n");
        }
    }

Startupapp.UseMiddleware<MyMiddleware1>(); 注册中间件

运行结果

  1. 实现IMiddleware
public class MyMiddleware2 : IMiddleware
    {
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            await context.Response.WriteAsync("MyMiddleware2 Start \n");

            await next.Invoke(context);

            await context.Response.WriteAsync("MyMiddleware2 End \n");
        }
    }

Startupapp.UseMiddleware<MyMiddleware2>(); 注册中间件

ConfigureServices中向IOC容器注册services.AddSingleton<MyMiddleware2>();

运行结果

查看源码看看这俩种方式的区别
class UseMiddlewareExtensions

关键代码

internal const string InvokeMethodName = "Invoke";
internal const string InvokeAsyncMethodName = "InvokeAsync";
public static IApplicationBuilder UseMiddleware(this IApplicationBuilder app, Type middleware, params object[] args);

如果实现IMiddleware

 if (typeof(IMiddleware).GetTypeInfo().IsAssignableFrom(middleware.GetTypeInfo()))
            {
                // IMiddleware doesn't support passing args directly since it's
                // activated from the container
                if (args.Length > 0)
                {
                    throw new NotSupportedException(Resources.FormatException_UseMiddlewareExplicitArgumentsNotSupported(typeof(IMiddleware)));
                }

                return UseMiddlewareInterface(app, middleware);
            }

从IOC容器获取IMiddlewareFactory

 private static IApplicationBuilder UseMiddlewareInterface(IApplicationBuilder app, Type middlewareType)
        {
            return app.Use(next =>
            {
                return async context =>
                {
                    var middlewareFactory = (IMiddlewareFactory)context.RequestServices.GetService(typeof(IMiddlewareFactory));
                    if (middlewareFactory == null)
                    {
                        // No middleware factory
                        throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoMiddlewareFactory(typeof(IMiddlewareFactory)));
                    }

                    var middleware = middlewareFactory.Create(middlewareType);
                    ///......
   public interface IMiddlewareFactory
    {
        IMiddleware Create(Type middlewareType);

        void Release(IMiddleware middleware);
    }

MiddlewareFactory 中的实现

public class MiddlewareFactory : IMiddlewareFactory
{
    private readonly IServiceProvider _serviceProvider;

    public MiddlewareFactory(IServiceProvider serviceProvider)
    {
        this._serviceProvider = serviceProvider;
    }

    public IMiddleware Create(Type middlewareType)
    {
        return ServiceProviderServiceExtensions.GetRequiredService(this._serviceProvider, middlewareType) as IMiddleware;
    }
}
有此可知,实现IMiddleware注册中间件,还需要将类注入到容器
另一种无约束注册
   var methods = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public);
                var invokeMethods = methods.Where(m =>
                    string.Equals(m.Name, InvokeMethodName, StringComparison.Ordinal)
                    || string.Equals(m.Name, InvokeAsyncMethodName, StringComparison.Ordinal)
                    ).ToArray();
查找方法Invoke InvokeAsync是否存在,存在即可。

==注意,当Response已经发生,不要改变响应中的关键信息,如 HTTP Status Code context-type,...,会发生错误==

END

参考

ASP.NET Core Middleware 博客园

ASP.NET Core Middleware microsoft

原文地址:https://www.cnblogs.com/DaWeiCnblogs/p/12169174.html

时间: 2024-11-02 06:50:50

dotnet core 中间件的相关文章

通过Swashbukle给DotNet Core Web API 增加自动文档功能

DotNet Core Web API给开发者提供了一个很好的框架来开发Restful的API.那么这些API接口该如何管理起来呢?Swagger是一个很好的选择,Swagger不需要开发者额外去维护接口文档,只要开发者的接口遵循Restful的规范,Swagger就会根据API接口生成文档. 对于前后端分离的开发模式,前后端开发者一般会先定义好接口,然后各自独立开发,后端开发者可以使用Swagger很快的生成没有业务逻辑的接口文档,接口返回的是Mock Data,这样前端开发人员就可以更早的开

ASP.NET Core中间件(Middleware)实现WCF SOAP服务端解析

ASP.NET Core中间件(Middleware)进阶学习实现SOAP 解析. 本篇将介绍实现ASP.NET Core SOAP服务端解析,而不是ASP.NET Core整个WCF host. 因为WCF中不仅仅只是有SOAP, 它还包含很多如消息安全性,生成WSDL,双工信道,非HTTP传输等. ASP.NET Core 官方推荐大家使用RESTful Web API的解决方案提供网络服务. SOAP 即 Simple Object AccessProtocol 也就是简单对象访问协议.

发布xxl-job executor dotnet core 执行器的实现

DotXxlJob [github][https://github.com/xuanye/DotXxlJob] xxl-job的dotnet core 执行器实现,支持XXL-JOB 2.0+ 1 XXL-JOB概述 [XXL-JOB][1]是一个轻量级分布式任务调度平台,其核心设计目标是开发迅速.学习简单.轻量级.易扩展.现已开放源代码并接入多家公司线上产品线,开箱即用.以下是它的架构图 2. 关于DotXxlJob产生 在工作中调研过多个任务调度平台,如Hangfire.基于Quatz.NE

dotnet core 之 gRPC

dotnet core gRPC 原文在本人公众号中,欢迎关注我,时不时的会分享一些心得 HTTP和RPC是现代微服务架构中很常用的数据传输方式,两者有很多相似之处,但是又有很大的不同.HTTP是一种规范性.通用性.非常标准的传输协议,几乎所有的语言都支持,如果要确保各平台无缝衔接,可以考虑使用HTTP协议,例如现在常规的RestFUL,整个传输过程通常使用Json数据格式.以至于不管是前端还是后端都可以很好的对接. RPC协议不仅仅是服务间通信协议,甚至是进程间也存在.可以降低诸多微服务之间调

centos 7 &amp;&amp; dotnet core 2.0 &amp;&amp; nginx &amp;&amp; supervisor

前提 系统:centos 7 目录:/home/wwwroot/www.wuball.com dotnet core 2.0 官方指引 sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc sudo sh -c 'echo -e "[packages-microsoft-com-prod]\nname=packages-microsoft-com-prod \nbaseurl=https://packages.mi

Asp.net core 中间件简单应用

Asp.net core中间件 ,处理http请求和响应的中间组件,对比起asp.net ,asp.net core 管道机制,可以说是帅气十足,简单直接.下面是通过中间件对一个请求的url 指定路由 新建webapi 项目 Startup类中Configure方法中添加处理中间件代码如下 public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app

dotnet core 使用 MongoDB 进行高性能Nosql数据库操作

好久没有写过Blog, 每天看着开源的Java社区流口水, 心里满不是滋味. 终于等到了今年六月份 dotnet core 的正式发布, 看着dotnet 社区也一步一步走向繁荣, 一片蒸蒸日上的大好景象. 不在绑定Windows, 相信众位dotneter的春天就要来了 废话不多说, 早就对dotnet core 跃跃欲试, 手头一个新项目也正计划使用dotnet core来开发. 正好自己做做调研, 就与大家分享一点使用MongoDB的经验. 首先, 安装VS Code, 并安装C#插件,

北京时间28号0点以后Scott Hanselman同志台宣布dotnet core 1.0 rtm

今日占住微信号头条的好消息<终于来了!微软.Net Core 1.0下载放出>.本人立马跑到官网http://dot.net看了一下,仍然是.net core 1.0 Preview 1版本. 看来该文所提供的下载链接应该是提前泄露的版本了吧. 有网友说,Red Hat DevNation的第二天也就是美太平洋时间27号上午(北京时间28号0点以后) Scott Hanselman同志才会登台宣布dotnet core 1.0 rtm. 查了一下dotnet cli tools 进度,如下:

dotnet Core 学习(一):环境搭建

1.环境搭建 Windows下环境搭建:http://www.microsoft.com/net/core#windowsvs2015 Linux下环境搭建:http://www.microsoft.com/net/core#linuxcentos Windows下VS Code环境配置: VS Code下载地址:https://code.visualstudio.com/ 安完成后,在VS Code中安装C#插件:C# for Visual Studio Code (powered by Om