I am having a lot of trouble getting custom model binding to work when posting x-www-form-urlencoded
data. I\'ve tried every way I can think of and nothing seems to
ModelBinder seem relatively better to use than MediaTypeFormatter. You do not need to register it globally.
I found another alternative to use model binder to bind complex object types in Web API. In model binder, I am reading request body as string and then using JSON.NET to deserialize it to required object type. It can be used to map array of complex object types as well.
I added a model binder as follows:
public class PollRequestModelBinder : IModelBinder
{
public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
var body = actionContext.Request.Content.ReadAsStringAsync().Result;
var pollRequest = JsonConvert.DeserializeObject<PollRequest>(body);
bindingContext.Model = pollRequest;
return true;
}
}
And then I am using it in Web API controller as follows:
public async Task<PollResponse> Post(Guid instanceId, [ModelBinder(typeof(PollRequestModelBinder))]PollRequest request)
{
// api implementation
}
I would recommend you reading the following blog post in which Mike Stall explains in details how model binding works in the Web API:
There are 2 techniques for binding parameters: Model Binding and Formatters. In practice, WebAPI uses model binding to read from the query string and Formatters to read from the body.
Here are the basic rules to determine whether a parameter is read with model binding or a formatter:
- If the parameter has no attribute on it, then the decision is made purely on the parameter’s .NET type. "Simple types" uses model binding. Complex types uses the formatters. A "simple type" includes: primitives, TimeSpan, DateTime, Guid, Decimal, String, or something with a TypeConverter that converts from strings.
- You can use a
[FromBody]
attribute to specify that a parameter should be read from the body.- You can use a
[ModelBinder]
attribute on the parameter or the parameter’s type to specify that a parameter should be model bound. This attribute also lets you configure the model binder.[FromUri]
is a derived instance of[ModelBinder]
that specifically configures a model binder to only look in the URI.- The body can only be read once. So if you have 2 complex types in the signature, at least one of them must have a [ModelBinder] attribute on it.
So if the source of your data is the request body then you can create a custom MediaTypeFormatter rather than a model binder.