1. 程式人生 > 其它 >.net Core 中介軟體記錄出入引數,異常資訊

.net Core 中介軟體記錄出入引數,異常資訊

技術標籤:.Net Coreasp.netc#後端

文章目錄


中介軟體記錄全域性日誌/出入引數:

日誌記錄中介軟體

遇到的問題(踩過的坑)

    • Specified method is not supported. 不支援指定的方法
    • Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead. 不允許同步操作。
    • Stream was not readable. 流不可讀取
    • A non-empty request body is required. 空的請求主體
    • Concurrent reading is not supported. 不支援併發讀取

Stream was not readable. 流不可讀取/Specified method is not supported. 不支援指定的方法

.net Core 3的Request.Body預設不允許設定位置,不允許讀取等
在這裡插入圖片描述
//啟用讀取request
httpContext.Request.EnableBuffering();
在這裡插入圖片描述

Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead. 不允許同步操作。

發生原因: .net Core 3以上Request.Body的流不允許同步讀取,使用

var requestContent = await requestReader.ReadToEndAsync(); 非同步讀取
await/ReadToEndAsync().Result; 同步讀取值

A non-empty request body is required. 空的請求主體

在讀取完後日志記錄下來,報這個錯誤,對比發現Body流的位置不在0了,導致控制器模型繫結的時候報錯.
在這裡插入圖片描述
request.Body.Position = 0;

完整程式碼

public async Task InvokeAsync(HttpContext httpContext)
        {

            //啟用讀取request
            httpContext.Request.EnableBuffering();
            //請求body
            using var requestReader = new StreamReader(request.Body);
            var requestContent = await requestReader.ReadToEndAsync();
            request.Body.Position = 0;

            //設定stream存放ResponseBody
            var responseOriginalBody = response.Body;
            using var memStream = new MemoryStream();
            response.Body = memStream;

            // 執行其他中介軟體
            await _next(httpContext);

            //處理執行其他中介軟體後的ResponseBody
            memStream.Position = 0;
            var responseReader = new StreamReader(memStream);
            var responseContent = await responseReader.ReadToEndAsync();
            memStream.Position = 0;
            await memStream.CopyToAsync(responseOriginalBody);
            response.Body = responseOriginalBody;
            this._factory.CreateLogger<LogRequestMiddleware>().LogInformation($"請求方式: {request.Method}    URL: {reqUrl} \r\n 引數: {requestContent}\r\n \r\n ");
            this._factory.CreateLogger<LogRequestMiddleware>().LogInformation($"日誌返回: {request.Method}    URL: {reqUrl} \r\n 引數: {responseContent}\r\n \r\n ");
        }

異常記錄中介軟體

非常簡單,沒什麼可說的

/// <summary>
    /// 異常記錄中介軟體
    /// </summary>
    public class ExceptionMiddleware
    {
        private readonly RequestDelegate _next;
        private ILoggerFactory _factory;

        /// <summary>
        /// 異常
        /// </summary>
        /// <param name="next"></param>
        /// <param name="factory"></param>
        public ExceptionMiddleware(RequestDelegate next, ILoggerFactory factory)
        {
            _next = next;
            this._factory = factory;
        }

        public async Task Invoke(HttpContext httpContext)
        {
            try
            {
                await _next.Invoke(httpContext);
            }
            catch (Exception ex)
            {
                await HandleError(httpContext, ex);
            }
        }

        /// <summary>
        /// 錯誤資訊處理方法
        /// </summary>
        /// <param name="context"></param>
        /// <param name="ex"></param>
        /// <returns></returns>
        private async Task HandleError(HttpContext context, Exception ex)
        {
            context.Response.StatusCode = 500;
            context.Response.ContentType = "application/json;";
            string errorMsg = $"\r\n錯誤訊息:{ex.Message}{Environment.NewLine}\r\n錯誤追蹤:{ex.StackTrace}";
            this._factory.CreateLogger<LogRequestMiddleware>().LogError(errorMsg);
            //處理各種異常
            ResponseBase<object> response = ResponseBase<object>.Error("系統錯誤");
            var respStr = response.ToJson();
            var by = Encoding.UTF8.GetBytes(respStr);
            await context.Response.Body.WriteAsync(by, 0, by.Length);
        }
    }

使用方法

寫在跨域/路由/靜態目錄等系統中介軟體之後, 控制器中介軟體之前.
app.UseMiddleware();
app.UseMiddleware();

.Net Core 過濾器記錄全域性日誌/出參入參