How do I do a custom modelbinder when binding from body?
asp.net, asp.net-web-api
Solution
I am looking into this as well.
WebApis Model Binder comes with two built in ValueProviders.
QueryStringValueProviderFactory & RouteDataValueProviderFactory
Which are searched when you call
context.ValueProvider.GetValue
This question has some code on how to bind data from the body.
how to pass the result model object out of System.Web.Http.ModelBinding.IModelBinder. BindModel?
You could create a custom ValueProvider to do this as well, probably a better idea - which will be searched for the value matching the key. The above link just does this within the model binder, which limits the ModelBinder to looking only in the body.
public class FormBodyValueProvider : IValueProvider
{
private string body;
public FormBodyValueProvider ( HttpActionContext actionContext )
{
if ( actionContext == null ) {
throw new ArgumentNullException( "actionContext" );
}
//List out all Form Body Values
body = actionContext.Request.Content.ReadAsStringAsync().Result;
}
// Implement Interface and use code to read the body
// and find your Value matching your Key
}
Problem
I've been trying to experiment with model binding to make our API easier to use. When using the API I can't get the model binding to bind when the data is in the body, only when it is part of the query. The code I have is: ``` public class FunkyModelBinder : IModelBinder { public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext) { var model = (Funky) bindingContext.Model ?? new Funky(); var hasPrefix = bindingContext.ValueProvider .ContainsPrefix(bindingContext.ModelName); var searchPrefix = (hasPrefix) ? bindingContext.ModelName + "." : ""; model.Funk = GetValue(bindingContext, searchPrefix, "Funk"); bindingContext.Model = model; return true; } private string GetValue(ModelBindingContext context, string prefix, string key) { var result = context.ValueProvider.GetValue(prefix + key); return result == null ? null : result.AttemptedValue; } } ``` When looking at the `ValueProvider` property on the `bindingContext` I only see `QueryStringValueProvider` and `RouteDataValueProvider` which I think means that if the data is in the body I won't get it. How should I do this? I would like to support posting data as either json or form-encoded.