.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共享時遇到的坑,歡迎大家共同探討。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM