如何在C#中创建类似FromQuery的自定义FromActionArguments参数特性?
实现仅从ActionArguments绑定参数的自定义特性
要实现你需要的[FromActionArguments]特性,核心是通过自定义绑定源和模型绑定器,让框架明确只从ActionArguments中获取参数值,彻底阻断其他绑定渠道。具体步骤如下:
1. 创建自定义绑定源标记特性
先定义一个特性,用来标识参数应从ActionArguments取值:
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public class FromActionArgumentsAttribute : BindingSourceAttribute { public FromActionArgumentsAttribute() : base(new BindingSource("ActionArguments", "Action Arguments", true, true)) { } }
这里的自定义绑定源被标记为不可重用,确保每次都从当前请求的ActionArguments中取数。
2. 实现自定义模型绑定器
编写绑定逻辑,直接从ActionContext.ActionArguments中提取参数值:
public class ActionArgumentsModelBinder : IModelBinder { public Task BindModelAsync(ModelBindingContext bindingContext) { if (bindingContext.ActionContext.ActionArguments.TryGetValue(bindingContext.FieldName, out var value)) { bindingContext.Result = ModelBindingResult.Success(value); } else { bindingContext.Result = ModelBindingResult.Failed(); } return Task.CompletedTask; } }
3. 关联特性与绑定器
在Program.cs(或Startup.cs)中配置MVC,将自定义特性和绑定器关联起来:
builder.Services.AddControllers(options => { // 注册规则:标记了FromActionArgumentsAttribute的参数,使用ActionArgumentsModelBinder options.ModelBinderProviders.Insert(0, new BinderTypeModelBinderProvider(typeof(ActionArgumentsModelBinder), new FromActionArgumentsAttribute())); });
4. 在Action中直接使用
现在可以直接用[FromActionArguments]标记参数,无需设置默认值,框架也不会尝试从其他来源绑定:
[HttpGet] public IActionResult Get([FromActionArguments] HashSet<string> set) { // 直接使用set即可,它已经被你的ActionFilter填充完成 return Ok(set); }
之前方法的问题说明
- 使用
[FromServices]:框架会默认尝试从DI容器解析该类型,未注册服务就会报错,和你用ActionFilter填充ActionArguments的逻辑完全不匹配。 - 使用
[BindNever]:该特性仅告知框架“不要从请求体/查询等来源绑定”,但框架仍会推断默认绑定源,当Action存在多个参数时,容易误判为多个body绑定参数,触发你遇到的错误。而自定义绑定源明确指定了唯一取值渠道,不会出现这个问题。
内容的提问来源于stack exchange,提问作者Tundy
相关产品推荐
相关产品推荐

