先来看一个代码,后端参数是两个string类型的数组
public void ArrayTest(string[] array1, string[] array2)
前端Ajax调用,分别传递null和空数组
$.ajax("/Home/ArrayTest", { type: "post", data: JSON.stringify({array1:null, array2:[]}), contentType: "application/json; charset=utf-8" });
contentType如果用默认的application/x-www-form-urlencoded; charset=UTF-8那么array2参数根本就不会被提交到后台,jQuery官方也不认为这是个bug,因为该类型以键值对形式提交数据,一个空数组似乎没法表示。
后端接收这2个参数竟然都是null,这不是我想要的。后端参数换成List<string>呢,情况更糟array1是一个初始化了的空集合,array2却是null。
原因就不分析了,反正我觉得这是微软的bug,坑还得自己填。
首先添加json的ValueProviderFactory替换原来的JsonValueProviderFactory
public sealed class JsonNetValueProviderFactory : ValueProviderFactory { public override IValueProvider GetValueProvider(ControllerContext controllerContext) { // first make sure we have a valid context if (controllerContext == null) throw new ArgumentNullException("controllerContext"); // now make sure we are dealing with a json request if ( !controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) return null; // get a generic stream reader (get reader for the http stream) StreamReader streamReader = new StreamReader(controllerContext.HttpContext.Request.InputStream); string bodyText = streamReader.ReadToEnd(); if (String.IsNullOrEmpty(bodyText)) { // no JSON data return null; } var JSONObject = JsonConvert.DeserializeObject(bodyText) as JObject; // create a backing store to hold all properties for this deserialization Dictionary<string, object> backingStore = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase); foreach (var item in JSONObject) { backingStore.Add(item.Key, item.Value); } // return the object in a dictionary value provider so the MVC understands it return new DictionaryValueProvider<object>(backingStore, CultureInfo.CurrentCulture); } }
这里用Json.Net进行反序列化,比原来的JavaScriptSerializer效率高,而且妈妈再也不用担心Json请求太大的问题了。
然后添加json的ModelBinder
public class JsonModelBinder : IModelBinder { private IModelBinder _defaultBinder = new DefaultModelBinder(); public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) { if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase)) return _defaultBinder.BindModel(controllerContext, bindingContext); var valueProviderResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName); if (valueProviderResult == null) return null; else return (((JToken)valueProviderResult.RawValue).ToObject(bindingContext.ModelType)); } }
最后修改Global.asax
ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault()); ValueProviderFactories.Factories.Add(new JsonNetValueProviderFactory()); ModelBinders.Binders.DefaultBinder = new JsonModelBinder();
ok大功告成,null是null,空是空。
这不是个完美的解决方案,填坑嘛,先填上再说,最终还是希望微软能修复这些个问题。