zoukankan      html  css  js  c++  java
  • .Net Core Web Api实践(一)中间件的使用

    前言:从2019年年中入坑.net core已半年有余,总体上来说虽然感觉坑多,但是用起来还是比较香的。本来我是不怎么喜欢写这类实践分享或填坑记录的博客的,因为初步实践坑多,文章肯定也会有各种错误,跟别人优秀的文章比起来,好像我写的东西没有什么存在的价值。但是入坑.net core以来,这种思想开始慢慢改变了,毕竟我依靠别人解决问题的文章也不尽是教科书般的存在,但是很使用。所以,把自己的实践过程记录出来,一方面是巩固和完善自己的技术栈,另一方能帮助到其他人,或者跟他人共同探讨,也不算闭门造轮子,自娱自乐了吧。.net core web api的实践记录,就由中间件的使用开始吧。

    1、必要的知识储备

    在阅读这篇文章的时候,我希望读者已经了解接口的逆变与协变、泛型、委托等知识点(个人认为这是了解.net各种框架的必备知识),同时也知道.net core的依赖注入、生命周期的相关内容(园子里前几名的大佬,对这块都有非常优秀的讲解,这里我就不作介绍,有需要的童鞋可以留言,我提供连接)。

    2、.net core webapi项目中配置中间件

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env)
            {
                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
    
                app.UseMiddleware<RequestMiddleware>();           
                app.UseMvc();
            }
    

      在项目的Startup.cs文件中,找到Configure方法,加上app.UseMiddleware<RequestMiddleware>(); 这里的RequestMiddleware就是自定义的中间件,我们可以简单看下UseMiddleware的定义:

     TMiddleware是一个泛型,使用UseMiddleware传递的就是自定义的中间件。

    3、自定义中间件的实现

    很遗憾我的反编译工具未能找到UseMiddleware的实现方法,但是结合官网上的介绍https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/write?view=aspnetcore-3.1),自定义的中间件需要构造函数来接收一个RequestDelegate对象,是关于HttpRequest的一个委托,另外还需要一个名为 Invoke 或 InvokeAsync 的公共方法,用于写一些HttpRequest的预处理逻辑。在我的项目中,我用它来进行参数预处理、登录预处理、Session预处理以及请求的转发功能。

    public class RequestMiddleware
        {
            private readonly RequestDelegate _next;
            private readonly IConfig config;
    
            public RequestMiddleware(RequestDelegate next, IConfig config)
            {
                _next = next;
                this.config = config;
            }
    
            public Task Invoke(HttpContext context)
            {
                context.Request.EnableRewind(); //支持context.Request.Body重复读取,内部调用了EnableBuffering方法,否则在使用部分方法或属性时会报错误System.NotSupportedException: Specified method is not supported,例如context.Request.Body.Position
                // && context.Request.Path.Value == "/api/Main"
                if (context.Request.ContentLength != null)
                {
                    Stream stream = context.Request.Body;
                    byte[] buffer = new byte[context.Request.ContentLength.Value];
                    stream.Read(buffer, 0, buffer.Length);
                    string querystring = Encoding.UTF8.GetString(buffer);
    
                    RequestMiddleParam requestEntity = Newtonsoft.Json.JsonConvert.DeserializeObject<RequestMiddleParam>(querystring);
                    if (requestEntity == null)
                    {
                        throw new Exception("无法处理的请求");
                    }
    
                    
                    string param = Newtonsoft.Json.JsonConvert.SerializeObject(requestMiddleMapParam);        //参数
                    //todo 参数校验
                    byte[] bs = Encoding.UTF8.GetBytes(param);    //参数转化为utf8码
    
                    //context.Request.Body.Seek(0, SeekOrigin.Begin);
                    //context.Request.EnableBuffering();
    
                    var ms = new MemoryStream();
                    context.Request.Body = ms;
                    context.Request.Body.Write(bs, 0, bs.Length);
    
                    context.Request.Body.Position = 0;   //重置context.Request.Body的Stream指针,否则报A non-empty request body is required.错误
                }
    
                // Call the next delegate/middleware in the pipeline
                return this._next(context);
            }
        }
    

      值得注意的是,构造函数可以使用Startup.cs中ConfigureServices方法里的注入项,上面实例代码中的IConfig就是的。(这里还有一个坑,就是中间件通过构造函数来接收services.AddDbContext的注入项,因为生命周期不一样)

    4、参数预处理遇到的坑

    以一个Post请求为例,参数是Json结构,为了判断Json参数中的某字段是否符合规则,就需要对其进行反序列化,校验完成后,再序列化填进Body对象中。这里注意下context.Request.EnableRewind();与context.Request.Body.Position = 0;两行代码的添加,因为是以流的形式读取和再写入参数,EnableRewind方法支持重复读取,而context.Request.Body.Position的归0则保证在重新将参数写入Body后,报A non-empty request body is required.错误。

    以上就是.net core中间件的简单介绍了,其实它的作用有些像asp.net的拦截器,将请求拦截做一些预处理,针对请求参数的处理、服务的转发,甚至登录校验等需求,都是个不错的选择。如果还想深入了解的同学,可自行去寻找UseMiddleware的实现方式。下一篇文章,我将介绍使用.net core + Redis + Session完成分布式Session共享时遇到的坑,欢迎大家共同探讨。

  • 相关阅读:
    Android平台下基于XMPP的IM研究
    Android File数据存储
    Android 获取屏幕分辨率的方式
    Android TabHost 动态修改图标或者动态改变标题
    Android DatePickerDialog用法
    SharedPreference Demo
    progressdialog 去边框
    [LCT学习时的一些笔记]
    [ZJOI2007]最大半连通子图
    【Matrixtree Theorem学习笔记】
  • 原文地址:https://www.cnblogs.com/BradPitt/p/12146409.html
Copyright © 2011-2022 走看看