2011-07-30 21 views
3

我已經成功地被用於的WebForms與AJAX相對複雜的參數設置(使用jQuery.ajax調用)調用(可以算出與經典的ASP.NET Web表單盒的方法) 。我們試圖嘗試在MVC 3中使用相同的方法,但似乎在MVC未能成功反序列化Dictionary數組時遇到了第一個障礙。問題MVC 3反序列化Dictionarys爲AJAX請求

,如果沒有問題,在ASP.NET WebForms的「經典」作品的方法是如下:

[WebMethod] 
public static JQGrid.JQGridData GetListForJQGrid(int? iPageSize, int? iPage, int? iMaxRecords, string sSortField, string sSortOrder, 
    Dictionary<string, string> dSearchOptions, Dictionary<string, object>[] aOriginalColumnDefinition, string[] aExtraDataColumns) 

而且下面是MVC 3相當於:(NB完全相同的名稱/參數 - 不同的返回類型,但我不認爲這是相關的)

[HttpPost] 
public JSONResult GetListForJQGrid(int? iPageSize, int? iPage, int? iMaxRecords, string sSortField, string sSortOrder, 
    Dictionary<string, string> dSearchOptions, Dictionary<string, object>[] aOriginalColumnDefinition, string[] aExtraDataColumns) 

隨着WebMethod所有的數據反序列化完美。但是,當調用MVC方法時,所有簡單的參數都會反序列化,但由於某些未知原因,Dictionary的數組作爲空數組到達。

因此,關閉了一些問題,那後面:

  • 有其他人遇到的問題與MVC 3字典的數組的反序列化?
  • 是否MVC 3默認情況下不使用System.Web.Script.Serialization.JavaScriptSerializer我覺得這就是ASP.NET的WebMethods引擎蓋下使用?
  • 我可以強制MVC 3使用System.Web.Script.Serialization.JavaScriptSerializer而不是它使用什麼?
  • 或者我錯過了什麼/我的方法應該略有不同?請注意,至少現在我們需要在傳統的ASP.NET WebMethods和MVC 3之間共享客戶端代碼,所以我們希望儘可能保持原樣。
  • 最後,我可以看到有一個可能的解決方法,可以用來尋找這個問題:POST json dictionary。這個解決方法是鎮上唯一的遊戲,還是因爲提出這個問題而有所改進?

jQuery的AJAX調用:

$.ajax(_oJQGProperties.sURL, //URL of WebService/PageMethod used 
{ 
    data: JSON.stringify(oPostData), 
    type: "POST", 
    contentType: "application/json", 
    complete: DataCallback 
}); 

例JSON.stringify(oPostData):

{ 
"dSearchOptions":{}, 
"aOriginalColumnDefinition": 
[ 
{"name":"ID","sortable":false,"hidedlg":true,"align":"right","title":false,"width":40}, 
{"name":"URL","sortable":false,"hidedlg":true,"align":"left","title":false,"width":250,"link":"javascript:DoSummat(this,'{0}');","textfield":"Name"}, 
{"name":"Description","sortable":false,"hidedlg":true,"align":"left","title":false,"width":620} 
], 
"aExtraDataColumns":["Name"], 
"_search":false, 
"iPageSize":-1, 
"iPage":1, 
"sSortField":"", 
"sSortOrder":"", 
"iMaxRecords":0 
} 

回答

1

很長一段時間得到更新,但我想我會分享我們得到了。原來,這個問題是一個錯誤 - 它的詳細信息可以在這裏找到:

錯誤: http://connect.microsoft.com/VisualStudio/feedback/details/636647/make-jsonvalueproviderfactory-work-with-dictionary-types-in-asp-net-mvc

解決方法: POST json dictionary

我們使用說明解決方法已被罰款。我不太清楚修復程序什麼時候發貨以及錯誤在哪裏。 (是嗎 。NET依賴/ MVC依賴等),如果別人知道我很想看看:-)

更新

我沒有聽說過猶若這是運(我假設它出去與MVC ?4),但在此期間,這可能是一種替代解決方案:

http://www.dalsoft.co.uk/blog/index.php/2012/01/10/asp-net-mvc-3-improved-jsonvalueproviderfactory-using-json-net/

更新2

這具有現在已經發貨與MVC 4.修復的問題仍然是MVC 3沒有解決,所以我現在寫它作爲一個博客張貼在這裏:

http://icanmakethiswork.blogspot.com/2012/10/mvc-3-meet-dictionary.html

1

我沒有與結合於字典陣列的任何經驗,但一個可能的解決是使用自定義模型綁定器。 Scott Hanselman在這個主題上有一篇博文,您可能會發現它很有用:分裂DateTime - 單元測試ASP.NET MVC自定義模型。

+0

謝謝Brian - 我會研究這個... –

1

我就遇到了這個問題了。找到這個SO帖子之後,我想升級到MVC4,但是在我的環境中同時做所有事情都太冒險了,所以要這樣做。

This link張貼在約翰尼賴利的答案看起來很有希望,但它需要扁平我的字典字符串。因爲我的MVC模型是雙向的(用於讀取和寫入),而且我真的希望能夠將字典結構傳遞給它。將兩個屬性保留爲一個值將是一個真正的痛苦。我會需要添加更多的測試,注意邊緣情況等。

約翰尼的JsonValueProviderFactory link似乎也很有希望,但有點神祕。我也不完全適應這種MVC的一部分。我只用了幾個小時來解決這個問題,所以我也通過了這個。

然後,我發現this link某處,並認爲「是的!這更像是我想要的!」。換句話說,通過使用自定義綁定來攻擊模型綁定問題。用其他東西替換其中的一個,並使用MVC的內置功能來做到這一點。不幸的是,這不起作用,因爲我的用例是T列表,T是我的模型。這完全不符合樣本。所以我砍掉了它,最終失敗了。

然後,我得到了一個燈泡時刻--JSON.NET沒有這個問題。我一直用它來做各種事情,從克隆對象到記錄到REST服務端點。爲什麼不模型綁定?所以我最終結束了這個,我的問題解決了。我認爲應該與幾乎任何工作 - 我相信JSON.NET =)

/// <summary> 
/// Custom binder that maps JSON data in the request body to a model class using JSON.NET. 
/// </summary> 
/// <typeparam name="T">Model type being bound</typeparam> 
/// <remarks> 
/// This binder is very useful when your MVC3 model contains dictionaries, something that it can't map (this is a known bug, fixed with MVC 4) 
/// </remarks> 
public class CustomJsonModelBinder<T> : DefaultModelBinder 
    where T : class 
{ 
    /// <summary> 
    /// Binds the model by using the specified controller context and binding context. 
    /// </summary> 
    /// <returns> 
    /// The bound object. 
    /// </returns> 
    /// <param name="controllerContext">The context within which the controller operates. The context information includes the controller, HTTP content, request context, and route data.</param><param name="bindingContext">The context within which the model is bound. The context includes information such as the model object, model name, model type, property filter, and value provider.</param><exception cref="T:System.ArgumentNullException">The <paramref name="bindingContext "/>parameter is null.</exception> 
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     HttpRequestBase request = controllerContext.HttpContext.Request; 
     request.InputStream.Position = 0; 
     var input = new StreamReader(request.InputStream).ReadToEnd(); 
     T modelObject = JsonConvert.DeserializeObject<T>(input); 
     return modelObject; 
    } 
} 

要應用的粘合劑,我添加的屬性,以我的模型參數。這會導致MVC3使用我的聯編程序而不是默認值。這樣的事情:

public ActionResult SomeAction(
    [ModelBinder(typeof(CustomJsonModelBinder<List<MyModel>>))] // This custom binder works around a known dictionary binding bug in MVC3 
    List<MyModel> myModelList, int someId) 
    { 

一個警告 - 我使用內容類型爲「application/json」的POST。如果你正在做一些形式或多部分數據,它可能會崩潰。