.NetCore WebAPI采坑之路(持續更新)


 

1、WebAPI新增日志過濾器or中間件后Action讀取到的請求Body為空問題

案例:

自定義了一個中間件,用於記錄每次訪問webapi的入參,以及引用了Swagger。

先看下面這段代碼:

 public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }
            app.UseMvc();

            //各種中間件  
            app.UseVisitLogger();
            app.UsAirExceptionHandler();
            app.UseHttpsRedirection();
            //SignalR
            app.UseSignalR(routes =>
            {
                routes.MapHub<TriageHub>("/triage", (options) =>
                {
                    //指定采取WebSoket協議進行雙工通訊
                    options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets;
                });
            });
       
            //swagger 
            app.UseSwagger();
            app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TestWebAPI"));
        }

  上面這段代碼看上去是不是人畜無害,沒啥問題。 恩,F5啟動后,我們試下執行post方式的webapi。執行結果是ok的,但是UseVisitLogger中間件里的

日志記錄卻沒有記錄webapi的訪問日志。

我們把Startup下的Configure方法改成下面這種方式:

   public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }       
            //各種中間件  
            app.UseVisitLogger();
            app.UsAirExceptionHandler();
            app.UseHttpsRedirection();
            //SignalR
            app.UseSignalR(routes =>
            {
                routes.MapHub<TriageHub>("/triage", (options) =>
                {
                    //指定采取WebSoket協議進行雙工通訊
                    options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets;
                });
            });
            app.UseMvc();
            //swagger 
            app.UseSwagger();
            app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "TestWebAPI"));
        }

  我們把UseMvc()放置 各類中間件的后面,再來試下webapi的post方式(post的入參是一個模型,不是基礎數據類型!)

 

 執行結果如上圖。。。這一次api執行失敗,但是日志記錄成功了,如下圖:

哎。。。是不是很坑。。目前先記錄下,還要想辦法怎么去解決

---------------------------------------------------------------------解決新增自定義中間件后執行帶模型Post請求400問題----------------------------------

原因: 因為自定義中間件里有一個是寫日志的,會將HttpContext對象的Request.Body對象(一個Steam對象)的讀取位置改變。原來的日志中間件是這樣寫的,如下:

      public async Task Invoke(HttpContext context)
        {
            visitLog = new VisitLog();
            HttpRequest request = context.Request;
            visitLog.Url = request.Path.ToString();
            visitLog.Headers = request.Headers.ToDictionary(k => k.Key, v => string.Join(";", v.Value.ToList()));
            visitLog.Method = request.Method;
            visitLog.ExcuteStartTime = DateTime.Now;
            using (StreamReader reader = new StreamReader(request.Body))
            {
                visitLog.RequestBody = reader.ReadToEnd();
            }

            context.Response.OnCompleted(ResponseCompletedCallback, context);
            await _next(context);
        }

  上面的 requst.Body 在通過ReadToEnd后實際上的context.Request.Body的讀取位置已經是最后了,在后續的中間件接收到的context因為讀取位置不是0而是內容的

長度,所以怎么都讀不到數據。這就是為什么post請求會出現400錯誤,因為到action那里的時候確實Requst.Body的內容他啥也沒讀到啊!!

現在找到了問題所在就好處理了,處理方式如下:

  public async Task Invoke(HttpContext context)
        {
            visitLog = new VisitLog();
            HttpRequest request = context.Request;
            visitLog.Url = request.Path.ToString();
            visitLog.Headers = request.Headers.ToDictionary(k => k.Key, v => string.Join(";", v.Value.ToList()));
            visitLog.Method = request.Method;
            visitLog.ExcuteStartTime = DateTime.Now;
            var originalRequestBody = request.Body;

            var requestBodyStream = new MemoryStream();
            await request.Body.CopyToAsync(requestBodyStream);
            //設置當前流的位置未0
            requestBodyStream.Seek(0, SeekOrigin.Begin);
            //這里ReadToEnd執行完畢后requestBodyStream流的位置會從0到最后位置(即request.ContentLength)
            visitLog.RequestBody = new StreamReader(requestBodyStream).ReadToEnd();
            //需要將流位置重置偏移到0,不然后續的action讀取不到request.Content的值
            requestBodyStream.Seek(0, SeekOrigin.Begin);

            context.Response.OnCompleted(ResponseCompletedCallback, context);
            context.Request.Body = requestBodyStream;
            await _next(context);
            context.Request.Body = originalRequestBody;
        }

  好啦,我們把流的讀取位置重新偏移下就好了!

 2、.NetCore項目智能提示英文更改為中文的方法

.NetCore下載后,在VS2017開發時候,智能提示是下圖這樣的:

很不爽是吧,尤其是我們這種英文渣。解決方案呢其實就是需要將框架里的Nuget包的注釋xml文件替換成中文版的(至少我是這么做的,其他辦法未知..)

首先從C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETCore\v4.5.1 這個目錄下將zh-Hans文件夾下的所有文件copy到

C:\Program Files\dotnet\sdk\NuGetFallbackFolder\microsoft.netcore.app\2.1.0\ref\netcoreapp2.1目錄下。 這里我是因為用的.NetCore2.1,如果

是2.0則將目錄里的2.1更改成2.0。 然后重新打開VS2017就可以發現智能提示是中文啦~~~~

 3、字符集GB2312引用錯誤處理

在對csv文件讀取時候亂碼,后來發現.NetCore需要安裝System.Text.Encoding.CodePages這個Nuget包,然后在類的構造函數里加上這一段代碼System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance)

 4、Linux上部署.NetCore站點端口號與launchSettings.json設置不一致的解決辦法

在Linux上部署站點絕對會出現這個問題,除非你的端口號恰巧就和默認的站點一致。不然你在launchSettings.json上的端口設置好后發現在Linux上啟動你的應用后監聽的端口不一致。 

如何解決呢?沒辦法,在dotnet命令后加urls參數。如:

dotnet HY.Admin.Host.dll --urls http://*:5001

 上面就是指定了端口5001,結果如下:

 


免責聲明!

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



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