如何拦截C# Web API中未进入Action的无效请求并记录日志?
解决方案:拦截Web API模型绑定失败的请求并记录日志
当请求因参数类型不匹配(比如int参数传入字符串)导致模型绑定失败时,Web API会直接返回400错误,不会进入Action方法。你之前尝试的ValidateInput配置和重写BadRequest方法无效,是因为这些操作针对的是MVC请求验证或主动触发的BadRequest响应,而非模型绑定失败的场景。下面是两种可行的实现方案:
方法1:重写无效模型状态响应工厂(推荐)
Web API通过IInvalidModelStateResponseFactory处理模型绑定失败的响应,你可以替换这个工厂类,在返回响应前完成日志记录:
步骤1:实现自定义响应工厂类
using System; using System.Linq; using System.Net; using System.Net.Http; using System.Text; using System.Web.Http; using System.Web.Http.Controllers; public class CustomInvalidModelStateResponseFactory : IInvalidModelStateResponseFactory { public HttpResponseMessage CreateErrorResponse(HttpRequestMessage request, HttpActionContext actionContext) { // 记录无效请求日志 LogInvalidRequest(request, actionContext.ModelState); // 返回自定义"请求无效"响应 return new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent("请求无效", Encoding.UTF8, "text/plain") }; } private void LogInvalidRequest(HttpRequestMessage request, ModelStateDictionary modelState) { // 读取请求体(POST/PUT等方法) string requestBody = string.Empty; try { var stream = request.Content.ReadAsStreamAsync().Result; stream.Position = 0; using (var reader = new System.IO.StreamReader(stream)) { requestBody = reader.ReadToEnd(); } } catch (Exception ex) { requestBody = $"读取请求体失败: {ex.Message}"; } // 收集绑定错误信息 var errorMessages = modelState.Values .SelectMany(v => v.Errors) .Select(e => e.ErrorMessage ?? e.Exception?.Message) .ToList(); // 写入数据库日志(替换为你的实际数据库操作) using (var dbContext = new YourDbContext()) { dbContext.RequestLogs.Add(new RequestLog { RequestMethod = request.Method.Method, RequestPath = request.RequestUri.PathAndQuery, RequestBody = requestBody, ErrorDetails = string.Join("; ", errorMessages), LogTime = DateTime.Now }); dbContext.SaveChanges(); } } }
步骤2:在WebApiConfig中替换默认工厂
打开App_Start/WebApiConfig.cs,在Register方法中添加以下代码:
public static void Register(HttpConfiguration config) { // ...其他路由配置... // 替换默认的无效模型状态响应工厂 config.Services.Replace(typeof(IInvalidModelStateResponseFactory), new CustomInvalidModelStateResponseFactory()); }
方法2:使用ActionFilter拦截请求
通过自定义ActionFilter,在Action执行前检查ModelState有效性,实现日志记录和响应返回:
步骤1:实现自定义ActionFilter
using System; using System.Net; using System.Net.Http; using System.Text; using System.Web.Http.Controllers; using System.Web.Http.Filters; public class LogInvalidRequestFilter : ActionFilterAttribute { public override void OnActionExecuting(HttpActionContext actionContext) { if (!actionContext.ModelState.IsValid) { LogInvalidRequest(actionContext.Request, actionContext.ModelState); // 直接返回自定义响应,终止后续流程 actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent("请求无效", Encoding.UTF8, "text/plain") }; } base.OnActionExecuting(actionContext); } // 日志记录逻辑同方法1中的LogInvalidRequest方法 private void LogInvalidRequest(HttpRequestMessage request, ModelStateDictionary modelState) { // ...复制方法1中的日志代码... } }
步骤2:注册全局过滤器
在WebApiConfig.cs的Register方法中添加:
config.Filters.Add(new LogInvalidRequestFilter());
关键说明
- 对于GET请求,请求体为空,可通过
request.RequestUri.Query获取URL中的查询参数,补充到日志中。 - 如果日志写入是异步操作,建议用
Task.Run()后台执行,避免阻塞请求响应流程。 - 两种方法都能捕获所有模型绑定失败的场景,包括参数类型不匹配、必填参数缺失等。
内容的提问来源于stack exchange,提问作者Andrew Toole
相关产品推荐
相关产品推荐

