Question

I created a VS 2012 MVC API project from scratch, loaded the Nuget "WebApiContrib.Formatting.Jsonp", added a route, the formatter, and tried to send parameters as serialized JSON as a JSONP request. How do I identify or access these parameters in the controller?

WebApiConfig:

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}/{format}",
    defaults: new { id = RouteParameter.Optional, 
        format = RouteParameter.Optional }
);
config.Formatters.Insert(0, new JsonpMediaTypeFormatter());

Api Method:

public IEnumerable<string> Get()
{
    return new string[] { "value1", "value2" };
}

JQuery:

$.ajax({
    type: 'GET',
    url: '/api/Values',
    data: JSON.stringify({ "message": "\"Hello World\"" }),
    contentType: "application/json; charset=utf-8",
    dataType: 'jsonp',
    success: function (json) {
        console.dir(json.sites);
    },
    error: function (e) {
        console.log(e.message);
    }
});

I've tried modifying the Api method to include:

Get( [FromUri] string value)
Get( [FromBody] string value)
Get( CustomClass stuff)
Get( [FromUri] CustomClass stuff)
Get( [FromBody] CustomClass stuff)

Where CustomClass is defined as:

public class CustomClass
{
    public string message { get; set; }
}

So far, none of these produce anything but null for the parameters. How should I wire up these parameters from the object posted in the querystring?

EDIT:

I can trick it by modifying the JQuery ajax to be:

data: {"value":JSON.stringify({ "message": "\"Hello World\"" })}

for which I can de-stringify the [FromUri] string value and get my strongly typed object.

Still, I'm expecting the data binder to de-serialize parameters in to strongly typed objects. What technique makes this happen?

Was it helpful?

Solution

You are making a GET request and in case of GET request there is no body only the URI. All the data you provide for the $.ajax() call will be put into URI, for example your EDIT version will generate URI like this:

.../api/Values?value=%7B%22message%22%3A%22%5C%22Hello%20World%5C%22%22%7D

(notice that the JSON will be also URL encoded).

Now the URI parameters in Web API are being bind with use of ModelBinderParameterBinding, which means that Web API will not use any MediaTypeFormatter (which outputs complex types), but a ModelBinder/ValueProvider (which in this case will output a simple type - string).

You can approach your scenario by implementing custom ModelBinder (remember to use proper classes and interfaces from ASP.NET Web API namespaces not ASP.NET MVC ones):

public class JsonModelBinder : IModelBinder
{
    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        ValueProviderResult valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
        if (valueProviderResult == null)
            return false;

        bindingContext.Model = JsonConvert.DeserializeObject(valueProviderResult.AttemptedValue, bindingContext.ModelType);

        return true;
    }
}

public class JsonModelBinderProvider : ModelBinderProvider
{
    public override IModelBinder GetBinder(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        return new JsonModelBinder();
    }
}

And attaching it to your parameter with ModelBinderAttribute:

public IEnumerable<string> Get([ModelBinder(typeof(JsonModelBinderProvider))]CustomClass value)
{
    return new string[] { "value1", "value2" };
}

You can find more details regarding the subject here:

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top