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

如何为指定控制器及Action方法注册自定义InputFormatter

实现自定义InputFormatter仅应用于特定控制器/Action

有两种常用方案可以实现这个需求,以下是具体做法:

方案一:通过自定义特性控制生效范围

这是最灵活的方式,通过标记特性来指定哪些控制器或Action可以使用该InputFormatter:

1. 创建自定义标记特性

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class UseCspReportInputFormatterAttribute : Attribute
{
}

2. 修改自定义InputFormatter,添加生效判断逻辑

重写CanRead方法,仅当当前请求的控制器或Action标记了上述特性时,才允许处理请求:

public class CSPReportInputFormatter : TextInputFormatter
{
    public CSPReportInputFormatter()
    {
        SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/csp-report"));
        SupportedEncodings.Add(Encoding.UTF8);
    }

    // 重写CanRead方法,限制生效范围
    public override bool CanRead(InputFormatterContext context)
    {
        // 先检查基础条件(媒体类型、编码是否匹配)
        if (!base.CanRead(context))
            return false;

        // 检查当前端点是否存在自定义特性
        var endpoint = context.HttpContext.GetEndpoint();
        return endpoint?.Metadata.GetMetadata<UseCspReportInputFormatterAttribute>() != null;
    }

    public override async Task<InputFormatterResult> ReadRequestBodyAsync(InputFormatterContext context, Encoding encoding)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        using var reader = new StreamReader(context.HttpContext.Request.Body);
        string responseString = await reader.ReadToEndAsync();

        var data = JsonConvert.DeserializeObject<ContentSecurityPolicyRequest>(responseString);

        return await InputFormatterResult.SuccessAsync(data);
    }
}

3. 在目标控制器/Action上标记特性

全局注册InputFormatter的代码保持不变,然后在需要的控制器或Action上添加特性:

// 给整个控制器标记
[UseCspReportInputFormatter]
[ApiController]
[Route("api/csp")]
public class CspReportController : ControllerBase
{
    [HttpPost("report")]
    public IActionResult ReceiveReport(ContentSecurityPolicyRequest report)
    {
        // 处理CSP上报逻辑
        return Ok();
    }
}

// 或者仅给单个Action标记
[ApiController]
[Route("api/other")]
public class OtherController : ControllerBase
{
    [HttpPost("csp-report")]
    [UseCspReportInputFormatter]
    public IActionResult HandleCspReport(ContentSecurityPolicyRequest report)
    {
        // 处理逻辑
        return Ok();
    }
}

方案二:移除全局注册,仅在特定控制器配置

如果不想全局注册该InputFormatter,可以通过控制器的依赖注入获取MvcOptions并添加,但这种方式灵活性较低:

1. 移除全局注册的代码

修改ConfigureServices,不再全局添加InputFormatter:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
}

2. 在目标控制器中添加InputFormatter

通过构造注入获取MvcOptions,添加自定义InputFormatter:

[ApiController]
[Route("api/csp")]
public class CspReportController : ControllerBase
{
    public CspReportController(MvcOptions mvcOptions)
    {
        // 检查是否已添加,避免重复注册
        if (!mvcOptions.InputFormatters.Any(f => f is CSPReportInputFormatter))
        {
            mvcOptions.InputFormatters.Insert(0, new CSPReportInputFormatter());
        }
    }

    [HttpPost("report")]
    public IActionResult ReceiveReport(ContentSecurityPolicyRequest report)
    {
        return Ok();
    }
}

注意:方案二会让该InputFormatter对所有匹配媒体类型的请求生效,但只有目标控制器的Action能接收解析后的模型,其他控制器即使收到application/csp-report类型的请求,也无法完成模型绑定。相比之下,方案一的控制精度更高。

内容的提问来源于stack exchange,提问作者Baibhav Shukla

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 03:16:19