Reputation: 498
So none of the existing questions answer this.
I have implemented a custom model binder for web api 2 as below
public class AModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(Type modelType)
{
return modelType == typeof(A) ? new AdAccountModelBinder() : null;
}
}
public class AModelBinder : DefaultModelBinder
{
private readonly string _typeNameKey;
public AModelBinder(string typeNameKey = null)
{
_typeNameKey = typeNameKey ?? "type";
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var providerResult = bindingContext.ValueProvider.GetValue(_typeNameKey);
if (providerResult != null)
{
var modelTypeName = providerResult.AttemptedValue;
SomeEnum type;
if (!Enum.TryParse(modelTypeName, out type))
{
throw new InvalidOperationException("Bad Type. Does not inherit from AdAccount");
}
Type modelType;
switch (type)
{
case SomeEnum.TypeB:
modelType = typeof (B);
break;
default:
throw new InvalidOperationException("Bad type.");
}
var metaData =
ModelMetadataProviders.Current
.GetMetadataForType(null, modelType);
bindingContext.ModelMetadata = metaData;
}
// Fall back to default model binding behavior
return base.BindModel(controllerContext, bindingContext);
}
Models are defined as below -
Public class A {}
Public Class B : A {}
Web Api Action as below -
[System.Web.Http.HttpPost]
[System.Web.Http.Route("api/a")]
[System.Web.Http.Authorize]
public async Task<HttpResponseMessage> Add([ModelBinder(typeof(AModelBinderProvider))]Models.A a)
{}
Registered my provider as a gentleman in Application_Start -
var provider = new AdAccountModelBinderProvider();
ModelBinderProviders.BinderProviders.Add(provider);
Still my custom Binder refuses to fire up.
I am lost. What am I missing?
Upvotes: 2
Views: 4218
Reputation: 4030
may be you need to add custom parameter binding rule in WebApiConfig?
config.ParameterBindingRules.Insert(0, GetCustomParameterBinding);
see example here: How to pass ObjectId from MongoDB in MVC.net
Upvotes: 0
Reputation: 218
You need to implement IModelBinder interface:
Look at the following example of Custom:
public class MyModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
try
{
bindingContext.Model = new TestClass();
//following lines invoke default validation on model
bindingContext.ValidationNode.ValidateAllProperties = true;
bindingContext.ValidationNode.Validate(actionContext);
return true;
}
catch
{
return false;
}
}
}
There are several ways to set a model binder. First, you can add a [ModelBinder] attribute to the parameter.
public HttpResponseMessage Get([ModelBinder(typeof(MyModelBinder))] TestClass objTest)
You can also add a [ModelBinder] attribute to the type. Web API will use the specified model binder for all parameters of that type.
[ModelBinder(typeof(MyModelBinder))]
public class TestClass
{
// ....
}
Finally, you can add a model-binder provider to the HttpConfiguration. A model-binder provider is simply a factory class that creates a model binder. You can create a provider by deriving from the ModelBinderProvider class. However, if your model binder handles a single type, it's easier to use the built-in SimpleModelBinderProvider, which is designed for this purpose. The following code shows how to do this.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var provider = new SimpleModelBinderProvider(
typeof(TestClass), new MyModelBinder());
config.Services.Insert(typeof(ModelBinderProvider), 0, provider);
// ...
}
}
With a model-binding provider, you still need to add the [ModelBinder] attribute to the parameter, to tell Web API that it should use a model binder and not a media-type formatter. But now you don't need to specify the type of model binder in the attribute:
public HttpResponseMessage Get([ModelBinder] TestClass objTestClass) { ... }
Upvotes: 2
Reputation: 1
I think, you should rather use DefaultModelBinder from namespace System.Web.ModelBinding / IModelBinder from namespace System.Web.Http.ModelBinder. I also think you did some not necessery thinks, like registering provider in Application_Start, as you are using ModelBinder directive.
For more details look at http://blog.learningtree.com/creating-a-custom-web-api-model-binder/
Upvotes: -1