You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何拦截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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 17:40:02