asp.net-mvc-3 - MVC3 下的路由损坏

标签 asp.net-mvc-3 asp.net-mvc-routing

在我们将应用程序升级到 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 到以下网址来访问此路由:

/api/1.0/items/3/serviceitem

我的 Controller 方法具有以下签名:

[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
  });
}

当我点击按钮,导致使用指定的 JSON 数据向 Controller 发送 POST 时,我得到与上面相同的错误。如果我不发送 JSON 数据,它就会起作用(因为 MVC 将使用 URL 部分作为我的方法的参数)。

这是我的重现解决方案的链接:http://www.mediafire.com/?77881176saodnxp

最佳答案

不,这方面没有任何改变。我喜欢将此类问题称为“状态无法重现”。

步骤:

  1. 使用默认模板创建新的 ASP.NET MVC 3 项目
  2. ItemsController 添加到项目中:

    public class ItemsController : Controller
    {
        [ActionName("Index")]
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult CreateServiceItem(int id)
        {
            return Content(id.ToString());
        }
    }
    
  3. 修改 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 }
        );
    }
    
  4. 修改 ~/Views/Home/Index.cshtml View ,使其如下所示:

    <script type="text/javascript">
        $.ajax({
            url: '/api/1.0/items/3/serviceitem',
            type: 'POST',
            success: function (result) {
                alert(result);
            }
        });
    </script>
    
  5. 点击F5运行项目

  6. 正如预期的那样,默认浏览器启动,AJAX 请求被发送到 Items Controller 的 CreateServiceItem 操作,该操作返回 id=3 字符串,它是这个收到警报的字符串。

结论:要么你没有显示你的实际代码,要么问题出在你的电视上。


更新:

现在您已经发布了一个可重现的示例,我知道问题是什么以及它与我的测试用例有何不同。在我的测试用例中,我执行了如下请求:

$.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);
    }
});

不再有模型名称变量。因此,当您尝试调用以下 Controller 操作时会发生冲突:

public ActionResult CreateServiceItem(int id)

如果模型未包装在请求中的正确对象中,则模型绑定(bind)器首先从 POST 请求中选取值,因为它的优先级高于 url 的值。这就是模型绑定(bind)器的工作方式:它首先查找已发布的数据。在 ASP.NET MVC 2 中,这工作正常,因为没有 JsonValueProviderFactory,因此 POST 请求中没有 id 参数。在 ASP.NET MVC 3 中引入了这一点,现在它有了值(value)。

我建议您的解决方法是将 JSON 包装在另一个对象中。

关于asp.net-mvc-3 - MVC3 下的路由损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7854934/

相关文章:

asp.net-mvc - 允许在 asp.net mvc 2 Controller 名称的 URL 中使用连字符

c# - MVC - 给定路由名称,我可以获得默认操作名称和 Controller 名称吗?

asp.net-mvc-2 - 区域内的自定义路由

asp.net-mvc - ASP MVC ChildActionOnly 应该有路由

c# - Action 参数命名

asp.net-mvc - ASP.NET MVC 从服务器读取文件

c# - 未绑定(bind)模型项时如何添加 ModelState.AddModelError 消息

asp.net-mvc-3 - ASP.NET MVC 3 Ninject 自定义成员资格和角色提供程序

asp.net-mvc - 在这个 ASP.NET MVC 3 应用程序中,我缺少什么来获得不显眼的客户端验证?

javascript - 将字符串列表传递给 mvc 3 Razor 中的 Controller