在webapi 项目中,经常需要记录异常信息和接口的请求详情,同时记录调用的接口异常的参数等数据以便后续追查,但是又不想在项目到处写try catch,此时可以通过全局过滤器进行记录,
代码如下
全局异常过滤器
WebApiExceptionFilterAttribute
namespace NetCore3WebApiTemplate.Filters
{
/// <summary>
/// api请求异常日志类
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class WebApiExceptionFilterAttribute : ExceptionFilterAttribute, IActionFilter
{
/// <summary>
/// 控制器中的操作执行之前调用此方法
/// </summary>
/// <param name="context"></param>
public void OnActionExecuting(ActionExecutingContext context)
{
//将请求的参数带上,后续使用
context.HttpContext.Items.Add("params", context.ActionArguments);
//请求开始实际带上
context.HttpContext.Items.Add("executeStartTime", DateTime.Now);
}
/// <summary>
/// 控制器中的操作执行之后调用此方法
/// </summary>
/// <param name="context"></param>
public void OnActionExecuted(ActionExecutedContext context)
{
// do nothing
}
/// <summary>
/// 控制器中的操作异常调用此方法
/// </summary>
/// <param name="actionExecutedContext"></param>
/// <returns></returns>
public override Task OnExceptionAsync(ExceptionContext actionExecutedContext)
{
if (actionExecutedContext.Exception != null)
{
///取消操作导致的异常忽略
if (actionExecutedContext.Exception is OperationCanceledException)
{
}
else
{
WriteErrorAsync(actionExecutedContext);
}
}
HttpResponseResultModel<string> result = new HttpResponseResultModel<string>();
result.HttpStatusCode = (HttpStatusCode)actionExecutedContext.HttpContext.Response.StatusCode;
result.IsSuccess = false;
result.ErrorMessage = "出现异常,请稍后重试";
result.ExceptionMessage = actionExecutedContext.Exception.ToString();
actionExecutedContext.Result = new ObjectResult(result);
return base.OnExceptionAsync(actionExecutedContext);
}
/// <summary>
/// 写异常日志
/// </summary>
/// <param name="exceptionContext"></param>
/// <returns></returns>
private async Task WriteErrorAsync(ExceptionContext exceptionContext)
{
WebApiExceptionLogModel logModel = new WebApiExceptionLogModel();
//获取Action 参数
var items = exceptionContext.HttpContext.Items;
logModel.ExecuteStartTime = DateTime.Parse(items["executeStartTime"].ToString());
logModel.ExecuteEndTime = DateTime.Now;
IDictionary<string, object> actionArguments = null;
if (items.ContainsKey("params"))
{
actionArguments = (IDictionary<string, object>)items["params"];
}
logModel.ActionParams = new Dictionary<string, object>(actionArguments);
logModel.HttpRequestHeaders = exceptionContext.HttpContext.Request.Headers.ToString();
logModel.HttpRequestPath = exceptionContext.HttpContext.Request.Path;
logModel.HttpMethod = exceptionContext.HttpContext.Request.Method;
logModel.ActionName = ((ControllerActionDescriptor)exceptionContext.ActionDescriptor).ActionName;
logModel.ControllerName = ((ControllerActionDescriptor)exceptionContext.ActionDescriptor).ControllerName;
logModel.TotalSeconds = (logModel.ExecuteEndTime - logModel.ExecuteStartTime).TotalSeconds;
logModel.ExceptionMessage = exceptionContext.Exception.ToString();
logModel.IP = CommonHttpContext.Current.Connection.RemoteIpAddress.ToString();
logModel.StatusCode = exceptionContext.HttpContext.Response.StatusCode;
}
}
}
全局日志过滤器 WebApiTrackerAttribute 代码如下
namespace NetCore3WebApiTemplate.Filters
{
/// <summary>
/// api 日志跟踪类
/// </summary>
public class WebApiTrackerAttribute : ActionFilterAttribute
{
/// <summary>
/// 控制器方法执行之前执行此方法
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
context.HttpContext.Items.Add("executeStartTime", DateTime.Now);
WriteLogAsync(context);
return base.OnActionExecutionAsync(context, next);
}
/// <summary>
/// 控制器操作结果执行之前调用此方法
/// </summary>
/// <param name="context"></param>
/// <param name="next"></param>
/// <returns></returns>
public override Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
return base.OnResultExecutionAsync(context, next);
}
/// <summary>
/// 控制器操作结果执行之后调用此方法
/// </summary>
/// <param name="context"></param>
public override void OnActionExecuted(ActionExecutedContext context)
{
base.OnActionExecuted(context);
}
/// <summary>
/// 写日志
/// </summary>
/// <param name="actionContext"></param>
/// <returns></returns>
private async Task WriteLogAsync(ActionExecutingContext actionContext)
{
var items = actionContext.HttpContext.Items;
DateTime executeStartTime = DateTime.Parse(items["executeStartTime"].ToString());
WebApiLogModel logModel = new WebApiLogModel();
logModel.ExecuteStartTime = executeStartTime;
logModel.ExecuteEndTime = DateTime.Now;
//获取Action 参数
logModel.ActionParams = new Dictionary<string, object>(actionContext.ActionArguments);
logModel.HttpRequestHeaders = actionContext.HttpContext.Request.Headers.ToString();
logModel.HttpRequestPath = actionContext.HttpContext.Request.Path;
logModel.HttpMethod = actionContext.HttpContext.Request.Method;
logModel.ActionName = ((ControllerActionDescriptor)actionContext.ActionDescriptor).ActionName;
logModel.ControllerName = ((ControllerActionDescriptor)actionContext.ActionDescriptor).ControllerName;
logModel.TotalSeconds = (logModel.ExecuteEndTime - logModel.ExecuteStartTime).TotalSeconds;
logModel.IP = CommonHttpContext.Current.Connection.RemoteIpAddress.ToString();
}
}
}
using System.Net;
namespace NetCore3WebApiTemplate.Core
{
/// <summary>
/// http请求结果类
/// </summary>
/// <typeparam name="T"></typeparam>
public class HttpResponseResultModel<T>
{
/// <summary>
/// http码
/// </summary>
public HttpStatusCode HttpStatusCode { get; set; }
/// <summary>
/// 是否成功
/// </summary>
public bool IsSuccess { get; set; }
/// <summary>
/// 返回结果
/// </summary>
public T BackResult { get; set; }
/// <summary>
/// 错误信息
/// </summary>
public string ErrorMessage { get; set; }
/// <summary>
/// 异常信息
/// </summary>
public string ExceptionMessage { get; set; }
}
}
namespace NetCore3WebApiTemplate.Utility
{
/// <summary>
/// webapi异常日志类
/// </summary>
public class WebApiExceptionLogModel: WebApiLogModel
{
/// <summary>
/// 异常信息
/// </summary>
public string ExceptionMessage { get; set; }
/// <summary>
/// 状态码
/// </summary>
public int StatusCode { get; set; }
}
}
using System;
using System.Collections.Generic;
using System.Text;
namespace NetCore3WebApiTemplate.Utility
{
/// <summary>
/// webapi 日志类
/// </summary>
public class WebApiLogModel
{
/// <summary>
/// 控制器名称
/// </summary>
public string ControllerName { get; set; }
/// <summary>
/// 方法名称
/// </summary>
public string ActionName { get; set; }
/// <summary>
/// 执行开始时间
/// </summary>
public DateTime ExecuteStartTime { get; set; }
/// <summary>
/// 执行结束时间
/// </summary>
public DateTime ExecuteEndTime { get; set; }
/// <summary>
/// 总耗时(秒)
/// </summary>
public double TotalSeconds { get; set; }
/// <summary>
/// 请求的Action 参数
/// </summary>
public Dictionary<string, object> ActionParams { get; set; }
/// <summary>
/// Http请求头
/// </summary>
public string HttpRequestHeaders { get; set; }
/// <summary>
/// 请求的路径
/// </summary>
public string HttpRequestPath { get; set; }
/// <summary>
/// 请求方法类型(POST,GET等)
/// </summary>
public string HttpMethod { get; set; }
/// <summary>
/// 请求的IP地址
/// </summary>
public string IP { get; set; }
}
}
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Text;
namespace NetCore3WebApiTemplate.Utility
{
public static class CommonHttpContext
{
private static IHttpContextAccessor accessor;
public static HttpContext Current => accessor.HttpContext;
internal static void Configure(IHttpContextAccessor accessor)
{
CommonHttpContext.accessor = accessor;
}
}
public static class StaticHttpContextExtensions
{
public static IApplicationBuilder UseStaticHttpContext(this IApplicationBuilder app)
{
var httpContextAccessor = app.ApplicationServices.GetRequiredService<IHttpContextAccessor>();
CommonHttpContext.Configure(httpContextAccessor);
return app;
}
}
public static class CommonServiceProvider
{
public static IServiceProvider ServiceProvider
{
get; set;
}
}
}
在startup的ConfigureServices中设置或禁用WebApiExceptionFilterAttribute或WebApiTrackerAttribute
/// <summary>
/// This method gets called by the runtime. Use this method to add services to the container.
/// </summary>
/// <param name="services"></param>
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(ops =>
{
ops.Filters.Add(new WebApiExceptionFilterAttribute());
ops.Filters.Add(new WebApiTrackerAttribute());
}).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
}
浙公网安备 33010602011771号