Contents

.Net Core Middleware 擷取 Request 參數

相信大家前期 debug 需要做這些事情,有時候每隻寫一隻印出來,不如全部印出來。但我不建議全部印出來。

Warning
這是一個新手入3個月寫的,品質不敢保證,但我目前用應該不會跑出任何錯誤。大致上除錯還算滿方便。

最終範例

設定檔isLogShowHeaderIsLogShowPostBody 看需求是不是要設定,預設為false

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
    public class RequestSpendTimeMiddleWare
    {
        private DateTime _startTime;

        private readonly RequestDelegate _next;
        private readonly ILogger<RequestSpendTimeMiddleWare> _logger;
        private readonly IConfiguration _configuration;

        public RequestSpendTimeMiddleWare(RequestDelegate next,
                                          ILogger<RequestSpendTimeMiddleWare> logger,
                                          IConfiguration configuration)
        {
            _next = next;
            _logger = logger;
            _configuration = configuration;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            _logger.LogInformation("┌-----------------------------------┐");
            _logger.LogInformation("Path: {path}", context.Request.Path);
            _logger.LogInformation("Method: {method}", context.Request.Method);
            bool isLogShowHeader = IsLogShowHeader();
            if (isLogShowHeader)
            {
                _logger.LogInformation("Header: {Header}", context.Request.Headers);
            }
            _logger.LogInformation("Content-Type: {contentType}", context.Request.ContentType);
            _logger.LogInformation("Query: {query}", context.Request.Query);
            bool IsLogShowPostBody = this.IsLogShowPostBody();
            _logger.LogInformation("showPostBody: {showPostBody}", IsLogShowPostBody);
            if (IsLogShowPostBody)
            {
                _logger.LogInformation("Body: {body}", await GetPostBody(context));
            }
            _startTime = DateTime.Now;
            // Call the next delegate/middleware in the pipeline
            await _next(context);

            _logger.LogInformation("執行花費:" + (DateTime.Now - _startTime).TotalSeconds.ToString() + "s");
            _logger.LogInformation("└-----------------------------------┘");
        }

        private bool IsLogShowHeader()
        {
            return _configuration.GetValue<bool>("IsLogShowHeader");
        }

        private bool IsLogShowPostBody()
        {
            return _configuration.GetValue<bool>("IsLogShowPostBody");
        }

        private static async Task<string> GetPostBody(HttpContext context)
        {

            if (context.Request.Method == "GET")
            {
                return "";
            }
            else if (context.Request.Method == "POST" && context.Request.ContentType.Contains("multipart/form-data;"))
            {
                return JsonConvert.SerializeObject(context.Request.Form); 
            }
            else
            {
                return await GetBody(context);
            }
        }

        private static async Task<string> GetBody(HttpContext context)
        {
            string body;
            context.Request.EnableBuffering();

            using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8, true, 1024, true))
            {
                body = await reader.ReadToEndAsync();
            }

            context.Request.Body.Position = 0;
            return body;
        }


    }

問題記錄

1
2
3
4
5
6
7
8
                using (var reader = new StreamReader(context.Request.Body))
                {
                    requestContent = await reader.ReadToEndAsync();
                    if (!string.IsNullOrEmpty(requestContent))
                    {
                        context.Request.Body.Seek(0, SeekOrigin.Begin);
                    }
                }

實際上跑出 錯誤。
https://i.imgur.com/gEjPgrd.png

解決方法

參照這篇c# - How to get HttpRequest body in .net core? - Stack Overflow寫法我們看到EnableRewind .Net Core不能用。後來這篇.NET Core 3.0 的重大變更 - .NET | Microsoft Docs看到改變寫法。

改完發現使用同步方法會有問題,找到Synchronous operations are disallowed. Call ReadAsync or set AllowSynchronousIO to true instead. - 天马3798 - 博客园調整設定就可以。但我覺得不需要這麼做,把程式調整非同步就能解決了。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
        private static async Task<string> GetBody(HttpContext context)
        {
            string body;
            context.Request.EnableBuffering();

            using (var reader = new StreamReader(context.Request.Body, Encoding.UTF8, true, 1024, true))
            {
                body = await reader.ReadToEndAsync();
            }

            context.Request.Body.Position = 0;
            return body;
        }

其他寫法,但我就不成功就是了,不知他們為什麼能跑…

ASP.NET Core 问题排查:Request.EnableRewind 后第一次读取不到 Request.Body - dudu - 博客园

舊版程式(留記錄,不要使用)

v1

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
    public class CheckXxxMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<CheckXxxMiddleware> _logger;
        private readonly IConfiguration _configuration;
        private readonly int HttpXxxValidResult = 400;

        public CheckXxxMiddleware(RequestDelegate next, ILogger<CheckXxxMiddleware> logger, IConfiguration configuration)
        {
            _next = next;
            _logger = logger;
            _configuration = configuration;
        }

        public async Task Invoke(HttpContext context)
        {
            string tsString = await GetTsString(context);

            if (string.IsNullOrEmpty(tsString))
            {
                context.Response.StatusCode = HttpCodeValidResult;
                return;
            }
            
            ...
        }
            
        private async Task<string> GetXxxString(HttpContext context)
        {
            string requestContent;
            _logger.LogInformation("Method:{method}", context.Request.Method);
            _logger.LogInformation("Path:{path}", context.Request.Path);
            _logger.LogInformation("Content-Type:{contentType}", context.Request.ContentType);
            _logger.LogInformation("Query:{query}", context.Request.Query);

            if (context.Request.Method == "POST" && context.Request.ContentType.Contains("multipart/form-data;"))
            {
                var data = context.Request.Form;
                _logger.LogDebug("data:{data}", data);
                if (data.ContainsKey("Xxx"))
                {
                    _logger.LogInformation("Xxx:{Xxx}", data["Xxx"]);
                    return data["Xxx"];
                }
            }
            else if (context.Request.Method == "POST" &&  context.Request.ContentType.Contains("application/x-www-form-urlencoded"))
            {
                context.Request.EnableBuffering();
                using (var reader = new StreamReader(context.Request.Body))
                {
                    requestContent = await reader.ReadToEndAsync();
                    if (!string.IsNullOrEmpty(requestContent))
                    {
                        context.Request.Body.Seek(0, SeekOrigin.Begin);
                    }
                }
                _logger.LogInformation("Body:{requestContent}", requestContent);
                if (requestContent != null)
                {
                    var queryString = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(requestContent);
                    _logger.LogInformation("queryString:{queryString}", queryString);

                    if (queryString.ContainsKey("Xxx"))
                    {
                        _logger.LogInformation("Xxx:{Xxx}", queryString["Xxx"]);
                    }
                    return queryString["Xxx"];
                }
            }
            else if (context.Request.Method == "POST" && context.Request.ContentType.Contains("json")) //application/json
            {
                context.Request.EnableBuffering();
                using (var reader = new StreamReader(context.Request.Body))
                {
                    requestContent = await reader.ReadToEndAsync();
                    if (!string.IsNullOrEmpty(requestContent))
                    {
                        context.Request.Body.Seek(0, SeekOrigin.Begin);
                    }
                }
                _logger.LogInformation("Body:{requestContent}", requestContent);

                if (requestContent != null)
                {
                    var dict = JsonConvert.DeserializeObject<Dictionary<string, string>>(requestContent);
                    _logger.LogInformation("dynamicObject:{d}", dict);

                    if (dict.ContainsKey("Xxx"))
                    {
                        _logger.LogInformation("Xxx:{Xxx}", dict["Xxx"]);
                        return dict["Xxx"];
                    }

                }
            }
            else
            {
                if (context.Request.Query.ContainsKey("Xxx"))
                {
                    return context.Request.Query["Xxx"];
                }
                
            }
            return null;
        }
    }