环境:.NetCore3.1、VS2019、Web API模板、SqlSugar、MSSqlServer
思路:我们要把每次HTTP请求响应的信息都保存到数据库,因为每次HTTP都会走一遍中间件,我们可以把写入数据库的操作写在自定义中间件上。但是它做的事情比较多,后续也可能变更需求,所有我决定把这个事情写在自定义服务上,让中间件注入该服务进行写入数据库操作。
1.新建服务对应的接口。
public interface IApiLogService
{
void DataSave(HttpContext context, long responseTime);
}
2.新建服务。
2.1.需要安装Nuget包sqlSugarCore,当然也可以使用其他ORM,本例只支持单例模式连接数据库的ORM。
2.2.添加数据库连接。需要在此数据库连接字符串上的服务器地址新建数据库,本人使用本地的SqlServer。
services.AddSingleton(new SqlSugarClient(new ConnectionConfig
{
ConnectionString = "server=.;uid=sa;pwd=sasa;database=apilogdemo;MultipleActiveResultSets=true",//必填, 数据库连接字符串
DbType = DbType.SqlServer, //必填, 数据库类型
IsAutoCloseConnection = true, //默认false, 时候知道关闭数据库连接, 设置为true无需使用using或者Close操作
InitKeyType = InitKeyType.SystemTable //默认SystemTable, 字段信息读取, 如:该属性是不是主键,是不是标识列等等信息
}));
public class ApiLogService : IApiLogService
{
private readonly IConfiguration _configuration;
private readonly SqlSugarClient _dbContext;
public ApiLogService(IConfiguration configuration, SqlSugarClient dbContext)
{
_configuration = configuration;
_dbContext = dbContext;
}
public void DataSave(HttpContext context, long responseTime)
{
var isLog = _configuration.GetValue<bool>("ApiLog:IsEnable");
if (isLog)
{
var requestMethod = context.Request.Method;
var requestURL = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path}";
//var accessToken = context.GetTokenAsync("access_token").Result;//添加身份验证的项目可以使用此方法获取到access_toekn
var accessToken = string.Empty;
var requestBody = string.Empty;
if (requestMethod == "POST")
{
context.Request.Body.Seek(0, SeekOrigin.Begin);
var _reader = new StreamReader(context.Request.Body);
requestBody = _reader.ReadToEnd();
}
_dbContext.Insertable(new ApiLog
{
AccessToken = accessToken,
AccessTime = DateTime.Now,
AccessAction = requestMethod,
AccessApiUrl = requestURL,
QueryString = context.Request.QueryString.ToString(),
Body = requestBody,
HttpStatus = context.Response.StatusCode,
ClientIP = context.Connection.RemoteIpAddress.ToString(),
ResponseTime = responseTime
}).ExecuteCommand();
}
}
}
2.3.需要在appsettion.json/appsetting.Development.json文件添加配置信息,用于控制是否启用响应日志,当然也可以不控制。
"ApiLog": {
"IsEnable": true
}
2.4.添加响应日志实体,需要在数据库上添加该表。
/// <summary>
/// 接口请求日志
/// </summary>
public class ApiLog
{
/// <summary>
/// Desc:
/// Default:
/// Nullable:False
/// </summary>
public int ALgID { get; set; }
/// <summary>
/// Desc:
/// Default:
/// Nullable:True
/// </summary>
public string ClientIP { get; set; }
/// <summary>
/// Desc:
/// Default:
/// Nullable:False
/// </summary>
public long ResponseTime { get; set; }
/// <summary>
/// Desc:
/// Default:
/// Nullable:True
/// </summary>
public string AccessToken { get; set; }
/// <summary>
/// Desc:
/// Default:
/// Nullable:False
/// </summary>
public DateTime AccessTime { get; set; }
/// <summary>
/// Desc:
/// Default:
/// Nullable:True
/// </summary>
public string AccessApiUrl { get; set; }
/// <summary>
/// Desc:
/// Default:
/// Nullable:True
/// </summary>
public string AccessAction { get; set; }
/// <summary>
/// Desc:
/// Default:
/// Nullable:True
/// </summary>
public string QueryString { get; set; }
/// <summary>
/// Desc:
/// Default:
/// Nullable:True
/// </summary>
public string Body { get; set; }
/// <summary>
/// Desc:
/// Default:
/// Nullable:False
/// </summary>
public int HttpStatus { get; set; }
}
3.此时,我们的服务已经定义好了。接下来是自定义一个中间件。
3.1.新建中间件,注入并使用刚才定义好的服务。
public class LogMiddleware
{
private readonly RequestDelegate _next;
private readonly IApiLogService _apiLogService;
private readonly IConfiguration _configration;
public LogMiddleware(RequestDelegate next, IApiLogService apiLogService, IConfiguration configration)
{
_next = next;
_apiLogService = apiLogService;
_configration = configration;
}
public Task Invoke(HttpContext context)
{
var watch = new Stopwatch();
watch.Start();
context.Response.OnStarting(() =>
{
var isLog = _configration.GetValue<bool>("ApiLog:IsEnable");
if (isLog)
{
watch.Stop();
_apiLogService.DataSave(context, watch.ElapsedMilliseconds);
}
return Task.CompletedTask;
});
return this._next(context);
}
}
3.2.新建暴露中间件扩展类。
public static class LogMiddlewareExtension
{
public static IApplicationBuilder UseLogMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<LogMiddleware>();
}
}
4.我们的工作已经做好了,接下来使用自定义的中间件就可以了。
4.1.添加自定义服务
services.AddSingleton<IApiLogService, ApiLogService>();
4.2.使用自定义中间件。
app.UseLogMiddleware();
5.运行项目,查看效果。
源码地址:https://github.com/Jcanc/WebApiResponseLog
写得不好,请温柔的喷。