Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I do a custom modelbinder when binding from body?

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.

like image 535
Tomas Jansson Avatar asked Mar 18 '13 09:03

Tomas Jansson


1 Answers

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
}
like image 71
Warren Avatar answered Nov 16 '22 00:11

Warren