We have an API with many actions that take an object Filter. However, when someone calls the API method and does not pass any parameters, we get a null reference. To avoid the need to check this everywhere, we want to change the model binding behavior so that for this type it returns a new instance instead of a null one.
In addition, we really do not want to write our own binder for the filter type, since it can change often.
We found a mechanism by which we can write ModelBinderParameterBinding , but then I can’t figure out how to add this item to the WebAPI configuration.
So, have we tried the right approach, and if so, how do we tell WebAPI to use our new parameter binding?
For reference, here is ModelParameterBindingModel ... I'm definitely not sure if this is production code! Since I can not run or test it :)
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);
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,
ModelMetadata = metadataProvider.GetMetadataForType(null, type),
ModelState = actionContext.ModelState,
ValueProvider = vp
};
return ctx;
}
}
source
share