3

Back in the day of ASP.NET MVC 3, I used JsonValueProviderFactory as per Phil Haack's Blog to bind JSON data as a Query String parameter to a strongly typed parameter.

Today, I find this isn't working. In MVC Web API, they seem to only bind POSTED JSON data to strongly typed objects (JSON in the body of the request), but not JSON data in the query string.

Is this the case with MVC 4 or what am I doing wrong?

My route:

routes.MapRoute(
    name: "CreateUser",
    url: "{controller}/CreateUser/{userAccount}",
    defaults: new { action = "CreateUser"} );

My method:

public JsonResult CreateUser( MyObjectType userAccount)
{   /* user is null */ }

My Class:

public class MyObjectType
{
    public string CardNumber {get;set;}
}

More tests:

// This completely fails, even if you URL Encode it:
localhost/CreateUser/{"CardNumber":"11111111"}

// Creates the object but all properties are null
localhost/CreateUser?{"CardNumber":"11111111"}
localhost/CreateUser?userAccount={"CardNumber":"11111111"}

I've also tried serializing all properties of the object even if we don't need the values, ensured the names are identical in spelling and in case, etc.

I can grab the parameter as string then deserialize it with JSON.NET without an issue, but I also want to use DataAnnotations to check the ModelState.IsValid.

Community
  • 1
  • 1
Zachary Scott
  • 20,968
  • 35
  • 123
  • 205

1 Answers1

2

It seems that in your case there is no way for framework to understand that the stuff you passed into querystring is JSON. Request to localhost/CreateUser/{"CardNumber":"11111111"} will be proceeded by route data value provider, so it will store a key-value: userAccount={"CardNumber":"11111111"}. Then DefaultModelBinder will ask for a value by key userAccount and will try to bind it to MyObjectType. At this spot he has no way of knowing that the value he got is an JSON string.

JsonValueProvider will engage only if request has contentType: application/json. If you send such a request with body {CardNumber:"1111111"} the provider will deserialize it into a dictionary from which DefaultModelBinder will easily grab the value.

vorou
  • 1,869
  • 3
  • 18
  • 35