diff --git a/Infrastructure/Infrastructure.csproj b/Infrastructure/Infrastructure.csproj
index d7e43deb..8e5ffc46 100644
--- a/Infrastructure/Infrastructure.csproj
+++ b/Infrastructure/Infrastructure.csproj
@@ -12,6 +12,7 @@
+
diff --git a/Infrastructure/Middleware/IApplicationBuilderExtension.cs b/Infrastructure/Middleware/IApplicationBuilderExtension.cs
new file mode 100644
index 00000000..cc98115d
--- /dev/null
+++ b/Infrastructure/Middleware/IApplicationBuilderExtension.cs
@@ -0,0 +1,20 @@
+using Microsoft.AspNetCore.Builder;
+
+namespace Infrastructure.Middleware
+{
+ ///
+ ///
+ ///
+ public static class ApplicationBuilderExtension
+ {
+ ///
+ /// 注入日志中间件
+ ///
+ ///
+ ///
+ public static IApplicationBuilder UseLogMiddleware(this IApplicationBuilder builder)
+ {
+ return builder.UseMiddleware();
+ }
+ }
+}
\ No newline at end of file
diff --git a/Infrastructure/Middleware/RequestResponseLoggingMiddleware.cs b/Infrastructure/Middleware/RequestResponseLoggingMiddleware.cs
new file mode 100644
index 00000000..cdaa9163
--- /dev/null
+++ b/Infrastructure/Middleware/RequestResponseLoggingMiddleware.cs
@@ -0,0 +1,150 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Microsoft.AspNetCore.Http;
+using Microsoft.Extensions.Logging;
+
+namespace Infrastructure.Middleware
+{
+ ///
+ /// 请求与返回中间件
+ ///
+ public class RequestResponseLoggingMiddleware
+ {
+ private readonly RequestDelegate _next;
+ private readonly ILogger _log;
+
+ ///
+ ///
+ ///
+ public RequestResponseLoggingMiddleware(RequestDelegate next, ILogger log)
+ {
+ _next = next;
+ _log = log;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public async Task Invoke(HttpContext context)
+ {
+ #region 这里可以加入正则验证context.Path。 过滤不需要记录日志的api
+
+ var path = context.Request.Path.ToString().ToLower();
+
+ if (path.Contains("/index") || path.Contains("/check") ||
+ path.Contains("/swagger") || path.Contains("/getsysdatas") || path.Contains("/load"))
+ {
+ await CatchNext(context);
+ return;
+ }
+
+ #endregion
+
+ // 启用耗时 日志记录
+ var stopwatch = new Stopwatch();
+ stopwatch.Start();
+ var logData = new Dictionary();
+ var request = context.Request;
+ logData.Add("request.url", request.Path.ToString());
+ logData.Add("request.headers",
+ request.Headers.ToDictionary(x => x.Key, v => string.Join(";", v.Value.ToList())));
+ logData.Add("request.method", request.Method);
+ logData.Add("request.executeStartTime", DateTimeOffset.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
+ //追踪实别器
+ logData.Add("traceIdentifier", context.TraceIdentifier);
+ // 获取请求body内容
+ if (request.Method.ToLower().Equals("post"))
+ {
+ // 启用倒带功能,就可以让 Request.Body 可以再次读取
+ request.EnableBuffering();
+ // 文件上传 记录文件信息
+ if (path.Contains("/upload"))
+ {
+ var content = string.Join(",", request.Form.Files.Select(item => item.FileName));
+ logData.Add("request.body", $"收到上传文件:{content}");
+ }
+ else
+ {
+ var sr = new StreamReader(request.Body, Encoding.UTF8);
+ //string content = sr.ReadToEnd(); //.Net Core 3.0 默认不再支持
+ var content = sr.ReadToEndAsync().Result;
+ logData.Add("request.body", content);
+ request.Body.Position = 0;
+ }
+ }
+ else if (request.Method.ToLower().Equals("get"))
+ {
+ logData.Add("request.body", request.QueryString.Value);
+ }
+
+ // 获取Response.Body内容
+ var originalBodyStream = context.Response.Body;
+ using (var responseBody = new MemoryStream())
+ {
+ context.Response.Body = responseBody;
+ await CatchNext(context);
+ if (!logData.ContainsKey("response.body"))
+ {
+ logData.Add("response.body", await GetResponse(context.Response));
+ }
+
+ logData.Add("response.executeEndTime", DateTimeOffset.Now.ToString("yyyy-MM-dd HH:mm:ss.fff"));
+ logData.Add("response.statusCode", context.Response.StatusCode);
+ await responseBody.CopyToAsync(originalBodyStream);
+ }
+
+ // 响应完成记录时间和存入日志
+ context.Response.OnCompleted(() =>
+ {
+ try
+ {
+ stopwatch.Stop();
+ logData.Add("elapsedTime", stopwatch.ElapsedMilliseconds + "ms");
+ var json = JsonHelper.Instance.Serialize(logData);
+ _log.LogInformation(json);
+ return Task.CompletedTask;
+ }
+ catch (Exception ex)
+ {
+ return Task.FromException(ex);
+ }
+ });
+ }
+
+ private async Task CatchNext(HttpContext context)
+ {
+ try
+ {
+ await _next(context);
+ }
+ catch (Exception ex)
+ {
+ _log.LogError(ex, "系统错误日志,管道捕获");
+ context.Response.StatusCode = 200;
+ context.Response.ContentType = "application/json; charset=utf-8";
+ var result = new { code = 500, message = ex.Message ?? "系统错误,请稍后再试" };
+ await context.Response.WriteAsync(JsonHelper.Instance.Serialize(result));
+ }
+ }
+
+ ///
+ /// 获取响应内容
+ ///
+ ///
+ ///
+ private static async Task GetResponse(HttpResponse response)
+ {
+ response.Body.Seek(0, SeekOrigin.Begin);
+ var text = await new StreamReader(response.Body).ReadToEndAsync();
+ response.Body.Seek(0, SeekOrigin.Begin);
+ return text;
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenAuth.WebApi/Startup.cs b/OpenAuth.WebApi/Startup.cs
index ea8d4a2f..79a73ac5 100644
--- a/OpenAuth.WebApi/Startup.cs
+++ b/OpenAuth.WebApi/Startup.cs
@@ -7,6 +7,7 @@ using Autofac;
using IdentityServer4.AccessTokenValidation;
using Infrastructure;
using Infrastructure.Extensions.AutofacManager;
+using Infrastructure.Middleware;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.Mvc;
@@ -110,14 +111,19 @@ namespace OpenAuth.WebApi
}
});
services.Configure(Configuration.GetSection("AppSetting"));
- services.AddControllers(option => { option.Filters.Add(); }).AddNewtonsoftJson(options =>
- {
- //忽略循环引用
- options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
- //不使用驼峰样式的key
- //options.SerializerSettings.ContractResolver = new DefaultContractResolver();
- options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
- });
+ services.AddControllers(option => { option.Filters.Add(); })
+ .ConfigureApiBehaviorOptions(options =>
+ {
+ // 禁用自动模态验证
+ options.SuppressModelStateInvalidFilter = true;
+ }).AddNewtonsoftJson(options =>
+ {
+ //忽略循环引用
+ options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
+ //不使用驼峰样式的key
+ //options.SerializerSettings.ContractResolver = new DefaultContractResolver();
+ options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
+ });
services.AddMemoryCache();
services.AddCors();
// todo:如果正式 环境请用下面的方式限制随意访问跨域
@@ -198,6 +204,9 @@ namespace OpenAuth.WebApi
app.UseRouting();
app.UseAuthentication();
+ // 启用日志追踪记录和异常友好提示
+ app.UseLogMiddleware();
+
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
//配置ServiceProvider