使用[FromUri]属性 - 将带有嵌套数组的复杂对象绑定

8

我希望在GET请求中通过URI发送一个包含嵌套数组的复杂对象到MVC操作方法中。

请考虑以下代码:

 public ActionResult AutoCompleteHandler([FromUri]PartsQuery partsQuery){ ... }

 public class PartsQuery
 {
     public Part[] Parts {get; set; }
     public string LastKey { get; set; }
     public string Term { get; set; }
 }

 $.ajax({ 
    url: "Controller/AutoCompleteHandler", 
    data: $.param({                                        
                      Parts: [{ hasLabel: "label", hasType: "type", hasIndex : 1 }],
                      LastKey : "Last Key",
                      Term : "Term"                             
                   }),
    dataType: "json", 
    success: function(jsonData) { ... }
 });

这在使用MVC Web Api中的默认模型绑定器时可以正常工作并正确地进行绑定。

但是,如果将其切换为普通的MVC而不是WebApi,则默认的模型绑定器会崩溃,并且无法绑定嵌套数组中对象的属性:

观察列表

partsQuery      != null          //Good
--LastKey       == "Last Key"    //Good
--Term          == "Term"        //Good
--Parts[]       != null          //Good
----hasLabel    == null          //Failed to bind
----hasType     == null          //Failed to bind
----hasIndex    == 0             //Failed to bind

我想知道为什么这在普通MVC中会出现问题,以及如何使FromUriAttribute在普通MVC中正确绑定该对象。

如果将 Part[] Parts 更改为 ICollection<Part> Parts 会发生什么?你能展示一下 Part 类的定义吗? - Erik Philips
现在正在尝试。这部分是简单的 POCO,具有公共 { get; set; } 属性。 - parliament
Part 是否有无参数的构造函数? - Erik Philips
ICollection没有解决绑定问题。它以前没有无参数的构造函数,但我刚试过了一个,仍然不行(尝试使用ICollection)。 - parliament
这个 Ajax 调用是否仍需要使用 Get 方法? - Erik Philips
是的,Erik,必须使用GET。除非有人能解决使用MVC使FromUriAttribute起作用的根本问题,否则我将在我的评论中使用正则表达式。 - parliament
1个回答

10

问题的核心在于MVC和WebApi使用不同的模型绑定器,即使基本接口也不同。

Mvc - System.Web.Mvc.IModelBinder
Web API - System.Web.Http.ModelBinding.IModelBinder

当您使用 $.ajax 调用发送数据时,您会发送以下查询字符串参数:

Parts[0][hasLabel]:label
Parts[0][hasType]:type
Parts[0][hasIndex]:1
LastKey:Last Key
Term:Term

虽然,与MVC默认模型绑定器绑定的正确格式对参数名称有不同的命名约定:

虽然与MVC默认模型绑定器绑定的正确格式对于参数的命名约定是不同的:

Parts[0].hasLabel:label
Parts[0].hasType:type
Parts[0].hasIndex:1
LastKey:Last Key
Term:Term

所以,这个方法调用将起作用:

$.ajax({ 
    url: "Controller/AutoCompleteHandler?Parts[0].hasLabel=label&Parts[0].hasType=type&Parts[0].hasIndex=1&LastKey=Last+Key&Term=Term",
    dataType: "json", 
    success: function(jsonData) { ... }
});

你需要根据MVC模型绑定命名约定构建你的查询字符串。

另外,在你的示例操作中使用的[FromUri]属性将被完全忽略,因为MVC DefaultModelBinder不知道它。


感谢您的回复,但我已经知道这些了。有两种可能的解决方案:一种是在客户端将URL字符串强制转换为正确的约定,我的问题在这里:http://stackoverflow.com/questions/17580471/javascript-regex-to-coerce-url-string-returned-from-param-into-mvc-model-bindi,或者创建一个自定义模型绑定程序来处理默认的$.param()约定,我的问题在这里:http://stackoverflow.com/q/17558735/1267778。但我认为最干净的解决方案可能是使MVC支持FromUri,这就是这个问题的目的。如果没有人能回答,我会标记您的答案。 - parliament
正则表达式是一个足够干净的解决方案,所以我将把你的答案标记为正确答案,因为它仍然很有价值。但是如果有人能够真正回答如何使FromUri在MVC中工作的真正问题,我会标记那个答案。谢谢。 - parliament
1
我认为在MVC控制器中使Web API绑定工作将是巨大的努力。管道完全不同,要调用Web API绑定,您必须正确实例化一堆低级Web API特定对象(HttpControllerDescriptor、HttpActionDescriptor、ModelBindingContext等)。 - Nenad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接