先來看一個代碼,后端參數是兩個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,空是空。
這不是個完美的解決方案,填坑嘛,先填上再說,最終還是希望微軟能修復這些個問題。