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

C#/ASP.NET MVC中如何为指定控制器及方法配置自定义输入格式化器

仅将自定义输入格式化器应用于特定控制器/动作的实现方案

针对你的需求,有两种常用实现方式,可根据场景选择:

方案一:自定义标记特性+格式化器条件判断

通过创建标记特性,让格式化器仅对标记了该特性的控制器/动作生效,保留全局注册但增加生效条件:

  1. 创建标记特性
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class UseCspReportFormatterAttribute : Attribute
{
}
  1. 修改自定义格式化器,重写CanRead方法添加生效条件
public class CSPReportInputFormatter : TextInputFormatter
{
    public CSPReportInputFormatter()
    {
        SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("application/csp-report"));
        SupportedEncodings.Add(Encoding.UTF8);
    }

    // 仅当控制器/动作标记了特性时才允许处理请求
    public override bool CanRead(InputFormatterContext context)
    {
        var actionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
        if (actionDescriptor == null) return false;

        // 检查控制器或动作是否标记了目标特性
        var hasControllerAttribute = actionDescriptor.ControllerTypeInfo.GetCustomAttribute<UseCspReportFormatterAttribute>() != null;
        var hasActionAttribute = actionDescriptor.MethodInfo.GetCustomAttribute<UseCspReportFormatterAttribute>() != null;
        
        return hasControllerAttribute || hasActionAttribute;
    }

    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);
    }
}
  1. 全局注册格式化器,并在目标控制器/动作上标记特性
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.InputFormatters.Insert(0, new CSPReportInputFormatter());
    });
}

// 给整个控制器标记,该控制器下所有动作都可使用该格式化器
[UseCspReportFormatter]
public class CspReportController : ControllerBase
{
    [HttpPost("submit-report")]
    public IActionResult SubmitCspReport(ContentSecurityPolicyRequest report)
    {
        // 处理CSP报告逻辑
        return Ok();
    }
}

// 或仅给单个动作标记
public class OtherController : ControllerBase
{
    [HttpPost("single-csp-endpoint")]
    [UseCspReportFormatter]
    public IActionResult SingleCspEndpoint(ContentSecurityPolicyRequest report)
    {
        // 处理逻辑
        return Ok();
    }
}

方案二:通过控制器约定仅给特定控制器添加格式化器

如果不需要针对单个动作做控制,只想给指定控制器批量添加格式化器,可以通过实现IControllerModelConvention完成:

  1. 创建控制器约定类
public class CspReportFormatterConvention : IControllerModelConvention
{
    private readonly CSPReportInputFormatter _formatter;

    public CspReportFormatterConvention()
    {
        _formatter = new CSPReportInputFormatter();
    }

    public void Apply(ControllerModel controller)
    {
        // 指定仅给CspReportController添加该格式化器
        if (controller.ControllerType == typeof(CspReportController))
        {
            controller.InputFormatters.Insert(0, _formatter);
        }
    }
}
  1. 注册约定
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(options =>
    {
        options.Conventions.Add(new CspReportFormatterConvention());
    });
}

这种方式下,只有CspReportController会拥有该输入格式化器,其他控制器不受影响。


内容的提问来源于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 02:17:11