DefaultModelBinder 无法反序列化作为 JSON 对象传递给操作的 .NET Dictionary 对象?
我有一个非常简单的类:
public class FilterItem
{
public Dictionary<string, string> ItemsDictionary { get; set; }
public FilterItem()
{
ItemsDictionary = new Dictionary<string, string>();
}
}
我想填充客户端字典中的数据,然后将其作为 JSON 对象传递给我的控制器操作。但是,无论我在客户端上尝试什么,DefaultModelBinder 似乎都无法反序列化它。
下面是一个调用我的操作的 javascript 代码示例:
var simpleDictionary = {"ItemsDictionary": {"1": "5", "2": "7"}};
$.ajax({ cache: false, type: "POST", data: JSON.stringify(simpleDictionary),
contentType: "application/json; charset=utf-8",
url: "/Catalog7Spikes/GetFilteredProductsJson", success: function (data) {...});
这是我的操作方法的简化版本:
[HttpPost]
public ActionResult GetFilteredProductsJson(FilterItem filterItem)
{
ProductsModel productsModel = new ProductsModel();
return View("SevenSpikes.Nop.UI.Views.Products", productsModel);
}
请注意,相反的工作方式。当作为 JsonResult 传递时,FilterItem 对象已成功序列化并作为 JSON 对象传递到客户端。然而试图反其道而行之是行不通的。
我读了 Connect 上的票证 并认为解决方法可行,但事实并非如此。
是否可以使用 ASP.NET MVC 3 中的 DefaultModelBinder 反序列化 .NET 字典?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
汉塞尔曼谈到了这一点:
来源:
http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
DefaultModelBinder 需要一些不太理想的语法字典。尝试使用这种语法:
它有点庞大,但它具有绑定性。以下也可以,但我个人更喜欢上面的;它更短。
Hanselman talks about this:
Source:
http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx
The
DefaultModelBinder
expects some less-than-optimal syntax for dictionaries. Try using this kind of syntax:It's kind of bulky but it binds. The following works as well, but I personally prefer the above; it's shorter.
更新
根据 Jeroen 的博客文章(请参阅下面他的答案,以及链接),以及重新审查代码后我的大脑闪现,我更新了 ExtendedJsonValueProviderFactory 这样它将始终为通过 JSON 提交的顶级字典正确创建 BackingStore。
该代码可在 GitHub 上找到: https://github.com/counsellorben/ASP.NET- MVC-JsonDictionaryBinding,工作示例位于 http://oss.form.vu/json-dictionary-example/。
通过删除当前的 JsonValueProviderFactory 并替换为可以处理字典创建的 JsonValueProviderFactory,您可以绑定字典。首先,正如 Keith 指出的那样,在 Javascript 中,请务必将字典包装在“filterItem”内,因为这是控制器操作中模型变量的名称,对于 JSON,这是控制器操作中变量的名称必须与返回的 Json 元素的名称匹配。此外,在传递类时,任何嵌套元素都必须与类中的属性名称匹配。
接下来,创建一个
ExtendedJsonValueProviderFactory
类,如下所示:您可能会注意到,该类几乎与标准 JsonValueProviderFactory 类相同,除了用于构建
Dictionary< 类型的 DictionaryValueProvider 条目的扩展之外。字符串,字符串>
。您还应该注意到,为了作为字典进行处理,元素必须具有以“Dictionary”结尾的名称(虽然我认为这是一个明显的代码味道,但我想不出另一个此时的替代方案......我愿意接受建议)。接下来,将以下内容添加到
Global.asax.cs
中的Application_Start
中:这将删除标准 JsonValueProviderFactory,并将其替换为我们的扩展类。
最后一步:享受美好。
UPDATE
Based upon the blog post by Jeroen (see his answer below, with the link), and a brain flash I had after re-reviewing my code, I have updated the ExtendedJsonValueProviderFactory so that it will always properly create a BackingStore for a top-level dictionary submitted via JSON.
The code is available on GitHub at https://github.com/counsellorben/ASP.NET-MVC-JsonDictionaryBinding, and a working example is at http://oss.form.vu/json-dictionary-example/.
By removing the current
JsonValueProviderFactory
and substituting one which can handle dictionary creation, you can bind your dictionary. First, as Keith pointed out, in your Javascript, be sure to wrap your dictionary inside of "filterItem", since this is the name of the model variable in your controller action, and for JSON, the name of the variable in the controller action must match the name of the Json element being returned. Also, when passing a class, any nested elements must match the names of the properties in the class.Next, create an
ExtendedJsonValueProviderFactory
class, as follows:You may notice that this class is almost identical to the standard JsonValueProviderFactory class, except for the extension to build an entry into the DictionaryValueProvider of type
Dictionary<string,string>
. You also should notice that, in order to be processed as a dictionary, an element must have a name ending in "Dictionary" (and while I think this is a significant code smell, I cannot think of another alternative at this time ... I am open to suggestions).Next, add the following to
Application_Start
inGlobal.asax.cs
:This will remove the standard JsonValueProviderFactory, and replace it with our extended class.
Final step: enjoy the goodness.
您尝试过以下方法吗?
Have you tried the following?
昨天,我在尝试将 JavaScript (JSON) 字典发布到控制器操作方法时遇到了完全相同的问题。我创建了一个自定义模型绑定器,它可以直接(在操作方法参数中)或包含在模型类中处理具有不同类型参数的通用字典。我只在 MVC 3 中测试过它。
有关我的经验和自定义模型绑定器的源代码的详细信息,请参阅我的博客文章 http://buildingwebapps.blogspot.com/2012/01/passing-javascript-json-dictionary-to.html
Yesterday I had exactly the same problem while trying to post a JavaScript (JSON) dictionary to a controller action method. I created a custom model binder that processes generic dictionaries with different type arguments, both directly (in a action method parameter) or contained in a model class. I have only tested it in MVC 3.
For the details of my experiences and the source code of the custom model binder, please see my blog post at http://buildingwebapps.blogspot.com/2012/01/passing-javascript-json-dictionary-to.html
默认模型绑定程序无法处理列表。
我在我的开源项目中解决了这个问题: http://jsaction.codeplex.com 并写了一篇关于此问题的文章问题:请阅读此处
http://jsaction.codeplex.com/wikipage?title=AllFeatures&referringTitle=文档
Default model binder cannot handle list.
I resolved this issue in my open source project: http://jsaction.codeplex.com and wrote an article about this issue: have a read here
http://jsaction.codeplex.com/wikipage?title=AllFeatures&referringTitle=Documentation