在我们将应用程序升级到MVC3之前,我有这条路线:
routes.MapRoute(
"Versioned API with Controller, ID, subentity",
"api/{version}/{controller}/{id}/{subentity}/",
new { controller = "API", action = "Index" },
new { id = @"\d+", subentity = "serviceitem|accessitem" }
),
我正试图使用POST命令到达以下URL:
/api/1.0/items/3/serviceitem
我的控制器方法有这个签名:
[ActionName("Index"), AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateServiceItem(int id)
当我尝试点击此方法时,出现以下错误:
The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int32' for method 'System.Web.Mvc.ActionResult CreateServiceItem(Int32)' in 'API.Controllers.ItemsController'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter. Parameter name: parameters
mvc2和mvc3之间是否有某种语法变化?
编辑:更新信息!
我想我找到了罪魁祸首。我将一些JSON数据的数据发布到URL。我的JSON对象看起来像这样:
{ Id: null, OtherProperty: 'foo' }
MVC3正在使用我的JSON对象中的Id而不是URL中指定的ID。这种行为是否可配置?
编辑2:可再现的例子:
我们在我们的应用程序中使用Ext,所以我的示例是使用Ext,但我可以重现它,这是在我的/Views/Home/Index.aspx中:
Ext.onReady(function() {
var w = new Ext.Window({
title: 'Hi there',
height: 400,
width: 400,
items: [
new Ext.Button({
text: 'Click me',
handler: function() {
var obj = {
Id: null,
Text: 'Hi there'
};
Ext.Ajax.request({
url: '/item/3/serviceitem',
method: 'POST',
jsonData: Ext.util.JSON.encode(obj),
headers: { 'Content-type': 'application/json' },
success: function(result, request) {
console.log(result);
},
failure: function(result, request) {
console.log(result);
}
});
}
})
]
});
w.show();
});
在我的Global.asax中,我有以下路线:
routes.MapRoute(
"Test",
"{controller}/{id}/{subentity}",
new { action = "Index" },
new { id = @"\d+", subentity = "serviceitem" }
);
在我的/ Controllers / ItemController中,我有这个方法:
[ActionName("Index")]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateServiceItem(int id)
{
string data;
using (StreamReader sr = new StreamReader(Request.InputStream))
{
data = sr.ReadToEnd();
}
return Json(new
{
DT = DateTime.Now,
Id = id,
PostedData = data
});
}
当我点击按钮,对控制器发出POST指定的JSON数据时,我得到与上面相同的错误。如果我不发送JSON数据,它可以工作(因为MVC将使用URL部分作为我的方法的参数)。
以下链接指向我的repro解决方案:http://www.mediafire.com/?77881176saodnxp
答案 0 :(得分:4)
不,在这方面没有任何改变。这是我喜欢称之为 status no repro 的问题。
步骤:
将ItemsController
添加到项目中:
public class ItemsController : Controller
{
[ActionName("Index")]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreateServiceItem(int id)
{
return Content(id.ToString());
}
}
修改Application_Start
中的路线注册,使其如下所示:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Versioned API with Controller, ID, subentity",
"api/{version}/{controller}/{id}/{subentity}",
new { controller = "API", action = "Index" },
new { id = @"\d+", subentity = "serviceitem|accessitem" }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
修改~/Views/Home/Index.cshtml
视图,使其如下所示:
<script type="text/javascript">
$.ajax({
url: '/api/1.0/items/3/serviceitem',
type: 'POST',
success: function (result) {
alert(result);
}
});
</script>
按 F5 运行项目
正如预期的那样,默认浏览器启动时,会向CreateServiceItem
控制器的Items
操作发送一个AJAX请求,该操作返回id = 3字符串,此字符串会被警告。< / p>
结论:要么你没有展示你的实际代码,要么就像我想说的那样,问题出在你的电视上。
更新:
现在您已经发布了一个可重现的示例,我看到问题是什么以及它与我的测试用例有何不同。在我的测试用例中,我执行了这样的请求:
$.ajax({
url: 'item/3/serviceitem',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ model: { id: null, text: 'Hi there' } }),
success: function (result) {
console.log(result);
}
});
在您的请求中,您正在执行此操作:
$.ajax({
url: 'item/3/serviceitem',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({ id: null, text: 'Hi there' }),
success: function (result) {
console.log(result);
}
});
不再有模型名称变量。因此,当您尝试调用以下控制器操作时会发生冲突:
public ActionResult CreateServiceItem(int id)
如果模型未包含在请求中的适当对象中,则模型绑定器首先从POST请求中选择值,因为它优先于url的值。这就是模型绑定器的工作原理:它首先查看POSTed数据。在ASP.NET MVC 2中,这工作正常,因为没有JsonValueProviderFactory
因此POST请求中没有id参数。在ASP.NET MVC 3中引入了这个,现在它有一个值。
我建议你使用的解决方法是将JSON包装在另一个对象中。