【问题标题】:How to define this route in ASP.NET MVC?如何在 ASP.NET MVC 中定义此路由?
【发布时间】:2010-01-16 16:22:07
【问题描述】:

我有一个名为Movie 的控制器,有一个名为ByYear 的动作,它以年份为参数:

    public ActionResult ByYear(int year)
    {
        ViewData["Title"] = string.Format("Movies released in {0}", year);
        var repository = MvcApplication.GetRepository();
        var movies = repository.Medias
                                .OfType<Movie>()
                                .Where(m => m.Year == year);
        return View("Index", movies);
    }

我想使用以下 URL 访问此操作:/Movie/ByYear/{year},但此操作的唯一有效路径是:/Movie/ByYear ?year={year}.

我尝试在我的应用程序的 RegisterRoutes 方法中添加新路由,但我找不到获得所需结果的方法...

谁能告诉我如何做到这一点?

注意:这实际上与this question 非常相似,但没有接受任何答案,最高投票的答案对我来说毫无意义,因为我对 MVC 完全陌生...

【问题讨论】:

    标签: c# asp.net-mvc routes


    【解决方案1】:

    将参数名称 year 更改为 id,这将匹配 MVC 添加到项目中的默认路由。

    所以为了进一步澄清,我们来看看ASP.NET MVC添加的默认路由:

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

    在此路由中,您可以看到三个专门为controlleraction 命名的令牌,传递给操作的第三个令牌是id。当请求进入您的应用程序时,ASP.NET MVC 将分析当前映射的路由,并尝试通过对您的控制器使用反射来找到与它们匹配的方法签名。

    当它查看您的Movie 控制器时,它会看到一个名为ByYear 的操作,但是该方法需要一个名为year 的整数,而不是id。这就是为什么当您为该特定操作创建 ActionLink 时,您最终会得到类似 /Movie/ByYear?year={year} 的内容。因此,要解决此问题,您有两种选择:

    解决此问题的第一个也是最简单的方法是更改​​ Action 的方法签名以接受名为 id 的参数,这是我在上面推荐的。这可以正常工作,但是当您稍后返回该源并想知道您为什么调用该参数 id 时,我可以看到它可能会在哪里引起一点混乱。

    第二种方法是添加另一个匹配该方法签名的路由。为此,您应该打开 Global.asax 并添加以下内容(未经测试,但应该可以):

    routes.MapRoute(
        "MoviesByYear",
        "Movies/ByYear/{year}",
        new { controller = "Movie", action = "ByYear" }
    );
    

    这个路由是硬编码的,是的,但它不会破坏你系统中的其他路由,它允许你调用方法参数year

    编辑 2:要注意的另一件事是,路由引擎将在它找到的与您的请求匹配的第一条路由上停止,因此任何像这样的自定义路由都应该添加到默认路由之前,这样您一定会找到的。

    【讨论】:

    • 但我不想称它为 id...这不是 id,它是一年。我不想为了让 MVC 路由系统开心而破坏我的代码的清晰度;)。无论如何,我在发布我的问题几分钟后自己找到了答案......
    • @Thomas。该操作称为 ByYear。我认为更改变量参数不会破坏清晰度。另一方面,远离默认路由无助于可维护性。
    • 是的,新路线的解决方案是我最终想出的……但这是否意味着我每次使用新参数名称创建操作时都必须创建新路线?!无论如何感谢您的解释
    • 是的,这就是为什么大多数人决定选择id :) -- 添加更多路线并不总是最好的解决方案,但也不一定是邪恶。请小心并确保彻底测试它们。
    • 另外,如果你仔细想想,id 代表标识符,对吧?您在 ByYear 操作中使用什么来识别电影?
    【解决方案2】:

    好的,我刚刚知道怎么做。我只需要默认路由之前创建新路由...我认为这个顺序没有任何意义

            routes.MapRoute(
                "MovieByYear",                                          // Route name
                "Movie/ByYear/{year}",                                  // URL with parameters
                new { controller = "Movie", action = "ByYear" }         // Parameter defaults
            );
    

    编辑:没有更简单的方法吗? (不涉及重命名参数)。我希望能够做这样的事情:

    [Route("/Movie/ByYear/{year}")]
    public ActionResult ByYear(int year)
    {
        ...
    

    【讨论】:

    • 虽然这是正确的,但我倾向于采用 Scott 的回答,以尽可能保持最少的路线数量。这样做所需的更改非常简单。
    • 是的,我明白你的意思了......但是当它实际上是一年时将参数命名为“id”可能会非常混乱,我绝对不希望这样。
    • 没有更简单的方法,因为它需要知道控制器,不幸的是不知道如何从 URL 中获取它。我也遇到过这个问题,不喜欢调用我所有的控制器方法参数“id”来匹配路由表,所以我做了你所做的
    • 通过方法属性路由绝对是我的首选方式...stackoverflow.com/questions/894779/…
    【解决方案3】:

    抛开设计考虑,如果你不想重命名参数,你可以添加类似下面的路由,它强制使用 year 参数

    routes.MapRoute(
         "MovieByYear",                        // Route name
         "Movie/ByYear/{year}",       // URL with parameters
         new { controller = "Movie", action = "ByYear" },
         new { year = @"\d+" }                 // Parameter defaults
    );
    

    【讨论】:

    • 这条路线将比电影控制器和 ByYear 动作匹配得多。我发现添加新路由时应该尽可能具体,只是因为有很多副作用。
    • +1 表示正则表达式约束...我真的有很多关于 MVC 的知识;)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    • 2020-04-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多