神魂顛倒論壇logo

icon
首頁Microsoft 應用技術區.NET / Visual Studio → 當ASP.NET MVC邂逅 -- jQuery.Ajax提交陣列

雷射溶脂 | 瘦小腹 | 植髮 | 眼袋 | 玻尿酸 | 電波拉皮 | Flash | 購物車 | Flash Player 11.2 | 豐胸 |

下一主題 上一主題


當ASP.NET MVC邂逅 -- jQuery.Ajax提交陣列


當ASP.NET MVC邂逅 -- jQuery.Ajax提交陣列 簡版






當ASP.NET MVC邂逅 -- jQuery.Ajax提交陣列

當ASP.NET MVC 透過JQuery的Ajax 提交陣列時,MVC的model binder機制就失效了。我們不得不在Controller裡面編寫自訂程式碼,將Request提交的資料轉換成需要的資料類別型。這個程序往往枯燥乏 味。下面以某專案的實際例子來展示如何解決這個問題,提供一個通用的解決方案。


需求描述


當使用者變更了設定,需要Ajax提交到伺服器。



圖片:


前端程式碼:

  1. var items = [];  
  2. $("input:checked").each(function () {  
  3.     items.push($(this).val());  
  4. $.ajax({  
  5.     type: 'post',  
  6.     url: 'Configure/Status',  
  7.     data: { answers: items }  

後端程式碼:

  1. public enum AnswerStatus  
  2.         Correct = 1,  
  3.         Incorrect = 2,  
  4.         Unanswered = 3 
  5. [HttpPost]  
  6. public ActionResult Status(IList<AnswerStatus> answers)  

這裡的answers始終為null. 神器fiddler出場,發現用JQuery.Ajax 提交Array的資料,提交的時候始終會在名稱後面加上」[]」, 問題就出在這裡。



圖片:


根據發現的結果修改程式碼:

  1. [HttpPost]  
  2. public ActionResult Status(IList<AnswerStatus> answers)  
  3.     answers = Request.Form.GetValues(「answers[]」).Select(d => d.ToEnum<AnswerStatus>(AnswerStatus.Unanswered).ToList();  

雖然這樣能夠透過解決我的問題,但每次提交Array都要這樣手動解析request,視乎一夜回到石器時代了。其實我們馬上會想到MVC 的Mode Binder。


嘗試進橫列第一次重構:

  1. public class AnswerModelBinder : IModelBinder  
  2.     public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)  
  3.         return controllerContext.RequestContext.HttpContext.Request.Form.GetValues(「answers[]」).Select(d => d.ToEnum<AnswerStatus>(AnswerStatus.Unanswered).ToList();      

硬編碼味道太重,換個類別型又得重寫,工作量跟之前比還視乎加入了,只是Controller變得優雅了。這種浪費青春又耗電的做法還是不符合要求。


進橫列第二次重構 : DefaultModelBinder 出場


萬能的DefaultModelBinder,能夠繫結任何類別型,可惜就是client傳過來的name後面多加了」[]」,導致DefaultModelBinder無法準確解析。那我們能不能欺騙DefaultModelBInder呢?


檢視ModelBindingContext發現有一個ModelName屬性,感覺有點像要繫結的引數的名稱,除錯追蹤發現ModelName確 實就是引數的名稱,那我們修改ModelName讓他跟client傳過來的name保持一致是否就能夠充分發揮DefaultModelBinder。 於是動手建立一個JQAjaxModelBinder


並繼承自DefaultModelBinder:

  1. public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)  
  2.     if(bindingContext.ModelType.IsEnumerable())  
  3.         var key = bindingContext.ModelName + "[]";  
  4.         var valueResult = bindingContext.ValueProvider.GetValue(key);  
  5.         if(valueResult != null && !string.IsNullOrEmpty(valueResult.AttemptedValue))  
  6.              bindingContext.ModelName = key;  
  7.     return base.BindModel(controllerContext, bindingContext);  
  8. }//如何使用自訂ModelBinder。該方法是Controller裡面的Action  
  9. public ActionResult Status([ModelBinder(typeof(ModelBinder.JQAjaxModelBinder))] IList<AnswerStatus> answers)  

這時,Controller裡面的Status (Action)方法已經能夠正確得到前端傳來的資料。並且還是強類型的。當然很多程式員都是懶惰的,筆者也是這其中一份子。筆者連Parameter前 面的引數([ModelBinder(typeof(ModelBinder.JQAjaxModelBinder))])都不想寫,那我們直接在 ModelBinders裡面註冊吧。其實註冊的時候也有點麻煩,必須設定Type,我那能提前知道有那些類別型啊。乾脆將 JQAjaxModelBinder設定成預設的ModerBinder,一勞永逸,再也沒有煩心事情了。


ModelBinder不同註冊方法


透過在Action方法的引數前面新增ModelBinder標籤,上文則是採用的這種方法。


資料類別型上面新增ModelBinder標籤

  1. [ModelBinder(typeof(ModelBinder.JQAjaxModelBinder))]  
  2. Public class User  

透過ModelBinders註冊

  1. ModelBinders.Binders.Add(typeof(User), new ModelBinder.JQAjaxModelBinder()); 

設定預設的ModerBinder

  1. ModelBinders.Binders.DefaultBinder = new ModelBinder.JQAjaxModelBinder(); 

後記: 當我們在開發的時候,經常做重複的事情,當一件事情重複多次後,我們就需要停下來認真思考,能不能將這些事情抽像出來,做一個通用的解決方案呢?一勞永逸的解決這些問題。


原文鏈結:http://www.cnblogs.com/coolite/archive/2012/12/24/JQModelBinder.html

 



購物車 | 回到頂部
Icon
網路的事情,讓網路解決

[ 逛網路就像是在探險 ]

    神 魂 顛 倒 T W G

http://bbs.flash2u.com.tw

http://tw.myblog.yahoo.com/flash2u-twg

http://flash-silverlight.blogspot.com/

http://flash2u.spaces.live.com/?_c02_owner=1
下一主題 上一主題