详解C#如何自定义书写中间件

 更新时间:2023年08月07日 16:50:07   作者:码农阿亮  
中间件是一种装配到应用管道以处理请求和响应的软件,是介于request与response处理过程之间的一个插件,本文主要介绍了如何自定义书写中间件,需要的可以参考下

一、什么是中间件

中间件是一种装配到应用管道以处理请求和响应的软件。是介于request与response处理过程之间的一个插件(一道处理过程),相对比较轻量级,并且在全局上会影响到request对象和response对象的属性。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。每个组件:

1、选择是否将请求传递到管道中的下一个组件。

2、可在管道中的下一个组件前后执行工作。

原理图:

多个中间件时,中间件请求和响应的中间件顺序相反

二、为什么使用中间件

在我们很多时候,当一个请求过来之后,我们想对这个请求做各种各样的操作和记录,这个时候我们可以加入中间件。目的就是对这个请求和响应做处理,其实不难理解,这就是类似于工业机器,一个商品出来之前会有很多关卡,会执行N到工序。最后加工出来的产品就是我们想要的,也是安全的。这些关卡就类似于中间件的作用了。

微软约定中间件需要两个参数,一个是httpcontext上下文对象,一个是Task类型的委托。通过上下文对象,处理请求,通过委托传递上下文对象到下一个中间件。核心就是一系列的请求委托,Run、Use、Map

  • Run:是最后一道工序,管道末尾。
  • Use:连接请求委托,next 向下走。
  • Map:扩展用作约定创建管道分支。

三、定义中间件

中间件的处理流程就像一个俄罗斯套娃,微软约定中间件需要两个参数,一个是httpcontext上下文对象,一个是Task类型的委托。通过上下文对象,处理请求,通过委托传递上下文对象到下一个中间件,这也是套娃模式的由来。RequestDelegate是管道的核心。ApplicationBuilder就是接收了很多个RequestDelegae把它拼到一起。

定义

/// <summary>
    /// 中间件定义和业务逻辑
    /// </summary>
    public class MyMiddleware
    {
        private readonly RequestDelegate _next;
        /// <summary>
        /// 构造
        /// </summary>
        /// <param name="next"></param>
        public MyMiddleware(RequestDelegate next)
        {
            _next = next;
        }
        /// <summary>
        /// 方法名必须命名为 Invoke或者 InvokeAsync,才能有效执行下一个中间件
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public async Task InvokeAsync(HttpContext httpContext)
        {
            /*
             * 在这里可以书写业务处理逻辑
             *中间件的处理流程就像一个俄罗斯套娃,微软约定中间件需要两个参数,一个是httpcontext上下文对象,一个是Task类型的委托。
             * 通过上下文对象,处理请求,通过委托传递上下文对象到下一个中间件(这也是套娃模式的由来)。
             */
            try
            {
                await _next(httpContext);
            }
            catch (Exception ex)
            {
                //内部出现异常
                httpContext.Response.StatusCode = 500;
            }
            finally
            {
                var statusCode = httpContext.Response.StatusCode;
                var msg = "";
                switch (statusCode)
                {
                    case 401:
                        msg = "未授权";
                        break;
                    case 403:
                        msg = "拒绝访问";
                        break;
                    case 404:
                        msg = "未找到服务";
                        break;
                    case 405:
                        msg = "405 Method Not Allowed";
                        break;
                    case 500:
                        msg = "服务器内部错误";
                        break;
                    case 502:
                        msg = "请求错误";
                        break;
                }
                if (!string.IsNullOrWhiteSpace(msg))
                {
                    await HandleExceptionAsync(httpContext, msg);
                }
            }
        }
        /// <summary>
        /// 处理Http响应异常
        /// </summary>
        /// <param name="httpContext"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        private async Task HandleExceptionAsync(HttpContext httpContext, string msg)
        {
            ErrorModel error = new ErrorModel
            {
                code = httpContext.Response.StatusCode,
                msg = msg
            };
            var result = JsonConvert.SerializeObject(error);
            httpContext.Response.ContentType = "application/json;charset=utf-8";
            await httpContext.Response.WriteAsync(result).ConfigureAwait(false);
        }
    }

封装拓展方法

创建一个中间件拓展类,为每个自定义中间件创建方法,通过IApplicationBuilder拓展方法暴露

/// <summary>
    /// 中间件拓展类
    /// </summary>
    public static  class MyMiddlewareExtensions
    {
        /// <summary>
        /// 将封装的中间件委托到一个类中,通过IApplicationBuilder拓展方法暴露
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        public static IApplicationBuilder UseMyMiddlewareOne(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<MyMiddleware>();
        }
        /*
         * 下面还可以拓展其他自定义中间件方法,通过IApplicationBuilder暴露
         */
    }

四、配置使用中间件

使用中间件

注意:使用中间件,顺序非常重要。比如此处,要放在权限处理的前面。不然请求从管道回来的时候,会先走消息处理,然后再判断权限,这样的话就无法处理了。因为使用多个中间件时,中间件请求和响应的顺序是相反的,此处还是爬楼看上面的原理图比较清晰。

 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                //开发环境使用
                app.UseSwagger();
                app.UseSwaggerUI(option =>
                {
                    foreach (string version in typeof(ApiVersions).GetEnumNames())
                    {
                        option.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"版本:{version}");
                    }
                });
            }
            app.UseRouting();
            //使用自定义中间件:
            app.UseMyMiddlewareOne();//注册自定义中间件
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

五、演示

定义测试Http接口:

    /// <summary>
        /// 自定义中间件测试
        /// </summary>
        /// <param name="param"></param>
        /// <returns></returns>
        [HttpGet]
        public int  MiddleWareTest(string param)
        {
            /*
             * note:此处的字符串是否是数字不做判断,当输入的非数字字符串时,强转Int服务内部会
             */
            int Number = int.Parse(param);
            return Number;
        }

Http请求测试:

到此这篇关于详解C#如何自定义书写中间件的文章就介绍到这了,更多相关C#中间件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C#基于Modbus三种CRC16校验方法的性能对比

    C#基于Modbus三种CRC16校验方法的性能对比

    这篇文章主要介绍了C#基于Modbus三种CRC16校验方法的性能对比,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • DevExpress之ChartControl用法实例总结

    DevExpress之ChartControl用法实例总结

    这篇文章主要介绍了DevExpress之ChartControl用法实例总结,需要的朋友可以参考下
    2014-08-08
  • C# 通过Socket读取大量数据的示例

    C# 通过Socket读取大量数据的示例

    这篇文章主要介绍了C# 通过Socket读取大量数据的示例,帮助大家更好的理解和学习使用c#,感兴趣的朋友可以了解下
    2021-03-03
  • C# DataTable的详细用法分享

    C# DataTable的详细用法分享

    在项目中经常用到DataTable,如果DataTable使用得当,不仅能使程序简洁实用,而且能够提高性能,达到事半功倍的效果,现对DataTable的使用技巧进行一下总结
    2013-11-11
  • 利用C#与PLC通信实现设备远程控制与管理

    利用C#与PLC通信实现设备远程控制与管理

    PLC是工业自动化中用于控制机械设备、生产线等的核心设备,通过与PLC的通信,我们可以实现设备的远程监控、数据采集等功能,C#作为一种现代化的编程语言,能够非常方便地与PLC进行通信,本文将介绍如何利用C#与PLC进行通信,并实现设备的远程控制与管理
    2025-02-02
  • C# 在项目中引用x86 x64的非托管代码的方法

    C# 在项目中引用x86 x64的非托管代码的方法

    使用宏最简单的方法是编译两个版本,编译多个版本可以点击配置管理器,然后创建x86和x64,然后版本添加宏,这样就可以判断宏来使用不同的dll。这篇文章主要介绍了C# 在项目中引用x86 x64的非托管代码的方法,需要的朋友可以参考下
    2018-03-03
  • C# WinForm开发中使用XML配置文件实例

    C# WinForm开发中使用XML配置文件实例

    这篇文章主要介绍了C# WinForm开发中使用XML配置文件实例,本文详细讲解了如何使用一个XML文件作为WinForm的配置文件,需要的朋友可以参考下
    2014-08-08
  • C#中Dapper的使用教程

    C#中Dapper的使用教程

    Dapper是一款轻量级ORM工具(Github),Dapper语法十分简单。并且无须迁就数据库的设计,今天通过本文给大家介绍C# Dapper的使用,感兴趣的朋友一起看看吧
    2021-07-07
  • c# 制作gif的四种方法

    c# 制作gif的四种方法

    这篇文章主要介绍了c# 制作gif的四种方法,帮助大家更好的理解和学习c#编程语言,感兴趣的朋友可以了解下
    2020-12-12
  • string与stringbuilder两者的区别

    string与stringbuilder两者的区别

    今天小编就为大家分享一篇关于string与stringbuilder两者的区别,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-01-01

最新评论