ExtJS的store.sync向Asp.net MVC的Action提交時引發System.Reflection.AmbiguousMatchException異常

來源:互聯網
上載者:User

ExtJs中的store在sync時,是可以批量提交資料的,所謂的批量是指如果在store中同時記錄了create、update、delete的對象時,分三次提交。在提交時,多個對象將被組合成JSON格式的字串,當要提交的資料只有一條時,JSON的字串如下所示:

{"ID":"a6d671ca-5480-4b5b-bf7a-b8459c0f598b","MobilePIN":"","Email":"111@ee.com","Password":"","CreateDate":null,"LastLoginDate":null,"LastPasswordChangedDate":null,"Comment":"","UserName":"user1","MobileAlias":"","LastActivityDate":null,"DisplayName":"","RememberMe":false}

如果是多條資料時,JSON的字串是:

[{"ID":"a6d671ca-5480-4b5b-bf7a-b8459c0f598b","MobilePIN":"","Email":"111@ee.com","Password":"","CreateDate":null,"LastLoginDate":null,"LastPasswordChangedDate":null,"Comment":"","UserName":"user1","MobileAlias":"","LastActivityDate":null,"DisplayName":"","RememberMe":false}]

在Controller的Action中,如果方法的簽名是public JsonResult CreateUser(UserDataObject user),則當傳入多條資料時,只能接收到第1條;當方法簽名是private List<UserDataObject> ProcessUsers(List<UserDataObject> users)時,當多條資料時沒有問題,可只有1條資料時,users為null值。

我想當然的想到在Action中直接把兩個方法都寫上,但結果報了System.Reflection.AmbiguousMatchException,即MVC的ActionSelector已經不能區分應該調哪個方法了。

經過尋找MVC的代碼,發現在AsyncActionMethodSelector的RunSelectionFilters方法中,將會尋找在Action上的Atrribute,像HttpPost這樣的Attribute都會做過濾,以判斷是否符合當前調用的上下文。

知道了這一點以後,我試想可以通過寫一個自訂的Attribute,然後根據當前Request請求的內容來決定哪個方法可用,哪個方法不可用,實現這個的關鍵點有兩個:

1、如何?這個Attribute。

2、如何得到Request的Post的內容並進行解決。

 

第1個問題很好解決,因為我還沒有系統的看MVC方面的資料,所以查看一下HttpPost可以知道它繼承了ActionMethodSelectorAttribute,這個類裡有一個抽象的方法IsValidForRequest。

第2個問題可以得到Request後,然後判斷當前Post的類型是否為application/json,進行對Post的資料進行JSON的還原序列化。經過測試得知,如果是單一對象的話,還原序列化化的對象是一個Dictionay<String,Object>對象,而多個對象得到的是一個Object[]。下面給出實現的源碼:

public class JsonModelPostAttribute : ActionMethodSelectorAttribute    {        public enum ParameterType        {            Single,            Multiple        }        private ParameterType _parameterType;        public ParameterType MethodParameterType        {            get            {                return _parameterType;            }            set            {                _parameterType = value;            }        }        public JsonModelPostAttribute()        {            _parameterType = ParameterType.Single;        }        public JsonModelPostAttribute(ParameterType type)        {            _parameterType = type;        }        public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)        {            var c = GetDeserializedObject(controllerContext);                        if (c == null)            {                return true;            }            if (MethodParameterType == ParameterType.Single)            {                return c is Dictionary<string, object>;            }            else            {                return c is object[];            }        }        private static object GetDeserializedObject(ControllerContext controllerContext)        {            if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))            {                // not JSON request                return null;            }            controllerContext.HttpContext.Request.InputStream.Seek(0, SeekOrigin.Begin);            StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);            string bodyText = reader.ReadToEnd();            controllerContext.HttpContext.Request.InputStream.Seek(0, SeekOrigin.Begin);            if (String.IsNullOrEmpty(bodyText))            {                // no JSON data                return null;            }            JavaScriptSerializer serializer = new JavaScriptSerializer();            object jsonData = serializer.DeserializeObject(bodyText);            return jsonData;        }    }

需要注意的時,在讀取了InputStream後,要重新將Position置為0,否則後續的JsonValueProviderFactory將得不到反序化執行個體,這樣即使能進入到正確的Action,參數也會為空白。

下面是Controller中的測試的程式碼片段:

        [AllowAnonymous]        [HttpPost]        [JsonModelPost(JsonModelPostAttribute.ParameterType.Multiple)]        public JsonResult CreateUser(List<UserDataObject> users)        {            ProcessUsers(users);            return this.Json(new { success = true, user = users }, JsonRequestBehavior.AllowGet);        }        private List<UserDataObject> ProcessUsers(List<UserDataObject> users)        {            int i = 1;            foreach (var user in users)            {                user.ID = Guid.Empty.ToString();                user.UserName = "Server Name" + i++;            }            return users;        }        [AllowAnonymous]        [HttpPost]        [JsonModelPost(JsonModelPostAttribute.ParameterType.Single)]        public JsonResult CreateUser(UserDataObject user)        {            var list = new List<UserDataObject>(new UserDataObject[] { user });            ProcessUsers(list);            return this.Json(new { success = true, user = list[0] }, JsonRequestBehavior.AllowGet);        }
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.