ASP.NET MVC 路由冲突 - 输入变量为空值

发布于 2024-08-20 22:03:34 字数 1109 浏览 7 评论 0原文

我不知道为什么我的路线会发生冲突。我的 Global.asax 文件中有这些:

        routes.MapRoute(
        "CustomerView", "{controller}/{action}/{username}",
        new { controller = "Home", action = "Index", username = "" }
        );

        routes.MapRoute(
        "Default", "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = "0" }
        );

到目前为止,一切都工作正常,除了当我像这样创建控制器操作时:

    public ActionResult MyAction(int id)
    {
        //Do stuff here
        return View();
    }

当我尝试通过 http://mydomain/MyController/MyAction/5 我得到:

“/”应用程序中的服务器错误。

参数字典包含一个 参数“id”的条目为空 不可为 null 的类型“System.Int32” 方法'System.Web.Mvc.ActionResult 跟踪(Int32)' in 'InTouch.Controllers.OrderController'。 使参数可选其类型 应该是引用类型或 可空类型。参数名称: 参数

表明 id 值未正确读取。当然,当我交换周围路线的顺序时,它工作得很好。到目前为止,我(诚然有限)的理解是,如果路由中指定的变量名称与控制器操作定义中指定的变量名称相匹配,则无论顺序如何,它都会假定该名称。显然我错了。交换顺序会导致其他控制器操作中断。在这种情况下处理我的路线的正确方法是什么?

I'm at a loss as to why my routes are conflicting. I have these in my Global.asax file:

        routes.MapRoute(
        "CustomerView", "{controller}/{action}/{username}",
        new { controller = "Home", action = "Index", username = "" }
        );

        routes.MapRoute(
        "Default", "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = "0" }
        );

So far everything has worked fine except when I created a controller action like so:

    public ActionResult MyAction(int id)
    {
        //Do stuff here
        return View();
    }

When I try viewing it through http://mydomain/MyController/MyAction/5 I get:

Server Error in '/' Application.

The parameters dictionary contains a
null entry for parameter 'id' of
non-nullable type 'System.Int32' for
method 'System.Web.Mvc.ActionResult
Track(Int32)' in
'InTouch.Controllers.OrderController'.
To make a parameter optional its type
should be either a reference type or a
Nullable type. Parameter name:
parameters

suggesting to me that the id value is not being read properly. Sure enoguh, when I swap the order of the routes around it works fine. My (admittedly limited) understanding so far was that, if a variable name specified in a route matches that specified in a controller action definition, it will assume that one regardless of order. Apparently I was wrong. Swapping the order causes other controller actions to break. What is the right way to handle my routes in this instance?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

丢了幸福的猪 2024-08-27 22:03:34

您的示例的问题在于匹配发生在第一条路线上,并且将“5”视为用户名参数。您可以使用约束来限制每个参数接受的值,以完成您想要的任务。由于接受 Id 的“默认”路由比“CustomerView”路由更具限制性,因此我将首先列出“默认”路由,并对 Id 参数进行限制:

routes.MapRoute(
    "Default", "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = "0" },
    new { id = @"\d+" } 
    );

这将导致第一个路由仅在 Id 为整数值。然后,所有其他请求将落入“CustomerView”路由,该路由将拾取没有整数作为第三个参数的任何其他请求。

查看创建路由约束 约束的解释。

The problem with your example is that the match is happening on the first route and it's seeing "5" as the username parameter. You can use constraints to limit what values are accepted for each parameter to accomplish what you're wanting. Since the "Default" route that accepts an Id is more restrictive than the "CustomerView" route, I would list the "Default" route first with a constraint on the Id parameter:

routes.MapRoute(
    "Default", "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = "0" },
    new { id = @"\d+" } 
    );

This will cause the first route to only match if Id is an integer value. All other requests would then fall through to the "CustomerView" route that would pick up any other requests that didn't have integers as that third parameter.

Check out Creating a Route Constraint for an explanation of constraints.

二智少女猫性小仙女 2024-08-27 22:03:34

我的理解(诚然有限)
到目前为止,如果变量名
路由中指定的匹配项
在控制器操作中指定
定义,它将假设一个
无论顺序如何。

路由值与操作参数的绑定发生在框架确定要使用的路由之后。路由选择是使用“第一个匹配获胜”启发式执行的:使用能够成功匹配传入请求的第一个路由,即使稍后定义了“更好”的路由。

迈克尔的解决方案是正确的。您需要首先列出默认路由,使用路由约束仅匹配 ID 为数字的 URL。接下来应该是限制较少的第二条路线。

注意:如果您遵循 Michael 的解决方案,如果您有任何用户的用户名仅包含数字,您将会遇到问题。您可以考虑在路由中添加一些其他区分因素,例如将关键字“user”放在第二个路由中:

routes.MapRoute(
    "Default", "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = "0" },
    new { id = @"\d+" } 
 );

routes.MapRoute(
    "CustomerView", "{controller}/{action}/user/{username}",
    new { controller = "Home", action = "Index", username = "" }
);

My (admittedly limited) understanding
so far was that, if a variable name
specified in a route matches that
specified in a controller action
definition, it will assume that one
regardless of order.

The binding of route values to action arguments happens AFTER the framework determines which route to use. Route selection is performed using a "first match wins" heuristic: the first route that can successfully match the incoming request is used, even if a "better" route was defined later.

Michael's solution is correct. You need to list the Default route first, using route constraints to only match URLs where the ID is numeric. Your second, less restrictive route should come next.

NOTE: If you follow Michael's solution you'll run into problems if you have any users with a username consisting only of numbers. You might consider adding some other discriminating factor to the routes, like putting the keyword "user" in the 2nd one:

routes.MapRoute(
    "Default", "{controller}/{action}/{id}",
    new { controller = "Home", action = "Index", id = "0" },
    new { id = @"\d+" } 
 );

routes.MapRoute(
    "CustomerView", "{controller}/{action}/user/{username}",
    new { controller = "Home", action = "Index", username = "" }
);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文