Let's assume we have the following simple ajax-call:

$.ajax({ url: "/somecontroller/someaction", data: JSON.stringify({ someString1: "", someString2: null, someArray1: [], someArray2: null }), method: "POST", dataType: "json", contentType: "application/json; charset=utf-8" }) .done(function (response) { console.log(response); });

The ajax call targets an action of an asp.net controller. The asp.net website has default ("factory") settings when it comes to the handling json-serialization with the only tweak being that Newtonsoft.Json.dll is installed via nuget and thus the web.config contains the following section:

<dependentAssembly> <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" /> </dependentAssembly>

The configuration sections for both webapi and mvc inside global.asax.cs have remained as they where. Having said all this, I noticed that if the controller 'somecontroller' is a webapi controller:

public class FooController : ApiController { public class Some { public string SomeString1 { get; set; } public string SomeString2 { get; set; } public long[] SomeArray1 { get; set; } public long[] SomeArray2 { get; set; } } [HttpPost] public IHttpActionResult Bar([FromBody] Some entity) { return Ok(new {ping1 = (string) null, ping2 = "", ping3 = new long[0]}); } }

then the data received in the c# world inside the 'someaction' method are like so:

entity.someString1: "", entity.someString2: null, entity.someArray1: [], entity.someArray2: null

However, if the controller is an mvc controller (mvc4 to be precise):

public class FooController : System.Web.Mvc.Controller { public class Some { public string SomeString1 { get; set; } public string SomeString2 { get; set; } public long[] SomeArray1 { get; set; } public long[] SomeArray2 { get; set; } } [HttpPost] public System.Web.Mvc.JsonResult Bar([FromBody] Some entity) { return Json(new { ping1 = (string)null, ping2 = "", ping3 = new long[0] }); } }

then the data received in the csharp world inside the method look like so:

entity.someString1: null, entity.someString2: null, entity.someArray1: null, entity.someArray2: null

It's apparent that there is a deviation between webapi and mvc controllers in terms of how deserialization of parameters works both when it comes to empty arrays and empty strings. I have managed to work around the quirks of the MVC controller so as to enforce the "webapi" behaviour both for empty strings and empty arrays (I will post my solution at the end for completeness).

My question is this:

Why does this deviation in regards to deserialization exists in the first place?

I can't come to terms that it was done merely for the sake of "convenience" given how much room the default mvc-settings leave for bugs that are just nerve-racking to discern and fix clearly and consistently at the action/dto-level.

Addendum: For anyone interested here's how I forced the mvc controller to behave the "webapi" way when it comes to deserializing parameters before feeding them into the action-methods:

//inside Application_Start ModelBinders.Binders.DefaultBinder = new CustomModelBinder_Mvc(); ValueProviderFactories.Factories.Remove( ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault() ); ValueProviderFactories.Factories.Add(new JsonNetValueProviderFactory_Mvc());

Utility classes:

using System.Web.Mvc; namespace Project.Utilities { public sealed class CustomModelBinder_Mvc : DefaultModelBinder //0 { public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { bindingContext.ModelMetadata.ConvertEmptyStringToNull = false; Binders = new ModelBinderDictionary { DefaultBinder = this }; return base.BindModel(controllerContext, bindingContext); } } //0 respect empty ajaxstrings aka "{ foo: '' }" gets converted to foo="" instead of null http://stackoverflow.com/a/12734370/863651 }

And