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