我们有一个包含许多操作的 API,这些操作需要Filter
目的。但是,当有人调用 API 方法并且不传递任何参数时,我们最终会得到空引用。为了避免在任何地方都必须检查这一点,我们希望改变模型绑定的行为,以便对于该类型它返回一个新实例而不是 null。
此外,我们真的不想为过滤器类型编写自己的活页夹,因为它可能会经常更改。
我们找到了一种机制,可以让我们写一个模型绑定器参数绑定 http://msdn.microsoft.com/en-us/library/system.web.http.modelbinding.modelbinderparameterbinding(v=vs.118).aspx但后来我不知道如何将该项目添加到 WebAPI 配置中。
那么,我们是否尝试了正确的方法?如果是,我们如何告诉 WebAPI 使用新的参数绑定?
作为参考,这里是 ModelParameterBindingModel...我绝对不确定这是生产代码!因为我无法运行或测试它:)
public class QueryFilterModelBinderParameterBinding : ModelBinderParameterBinding
{
private readonly ValueProviderFactory[] _valueProviderFactories;
private readonly IModelBinder _binder;
public QueryFilterModelBinderParameterBinding(HttpParameterDescriptor descriptor,
IModelBinder modelBinder,
IEnumerable<ValueProviderFactory> valueProviderFactories)
: base(descriptor, modelBinder, valueProviderFactories)
{
if (modelBinder == null)
{
throw new ArgumentNullException("modelBinder");
}
if (valueProviderFactories == null)
{
throw new ArgumentNullException("valueProviderFactories");
}
_binder = modelBinder;
_valueProviderFactories = valueProviderFactories.ToArray();
}
public new IEnumerable<ValueProviderFactory> ValueProviderFactories
{
get { return _valueProviderFactories; }
}
public new IModelBinder Binder
{
get { return _binder; }
}
public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
{
var ctx = GetModelBindingContext(metadataProvider, actionContext);
var haveResult = _binder.BindModel(actionContext, ctx);
//here's where we instantiate an empty filter if we cannot bind one
var model = haveResult ? ctx.Model : new QueryFilter();
SetValue(actionContext, model);
return Task.FromResult(model);
}
private ModelBindingContext GetModelBindingContext(ModelMetadataProvider metadataProvider, HttpActionContext actionContext)
{
var name = Descriptor.ParameterName;
var type = Descriptor.ParameterType;
var prefix = Descriptor.Prefix;
var vp = new CompositeValueProviderFactory(_valueProviderFactories).GetValueProvider(actionContext);
var ctx = new ModelBindingContext()
{
ModelName = prefix ?? name,
FallbackToEmptyPrefix = prefix == null, // only fall back if prefix not specified
ModelMetadata = metadataProvider.GetMetadataForType(null, type),
ModelState = actionContext.ModelState,
ValueProvider = vp
};
return ctx;
}
}