C#/ASP.NET MVC中如何为指定控制器及方法配置自定义输入格式化器
仅将自定义输入格式化器应用于特定控制器/动作的实现方案
针对你的需求,有两种常用实现方式,可根据场景选择:
方案一:自定义标记特性+格式化器条件判断
通过创建标记特性,让格式化器仅对标记了该特性的控制器/动作生效,保留全局注册但增加生效条件:
- 创建标记特性
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)] public class UseCspReportFormatterAttribute : Attribute { }
- 修改自定义格式化器,重写
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); } }
- 全局注册格式化器,并在目标控制器/动作上标记特性
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完成:
- 创建控制器约定类
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); } } }
- 注册约定
public void ConfigureServices(IServiceCollection services) { services.AddControllers(options => { options.Conventions.Add(new CspReportFormatterConvention()); }); }
这种方式下,只有CspReportController会拥有该输入格式化器,其他控制器不受影响。
内容的提问来源于stack exchange,提问作者Baibhav Shukla
相关产品推荐
相关产品推荐

