码迷,mamicode.com
首页 > Web开发 > 详细

dotnet core 中间件

时间:2020-01-09 01:20:07      阅读:111      评论:0      收藏:0      [点我收藏+]

标签:lin   ext   rom   environ   源码   semi   length   factory   运行   

## 官方说明

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

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

请求委托用于生成请求管道。 请求委托处理每个 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

dotnet core 中间件

标签:lin   ext   rom   environ   源码   semi   length   factory   运行   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!