【问题标题】:ASP.NET MVC Custom Routing Based on Query Params基于查询参数的 ASP.NET MVC 自定义路由
【发布时间】:2014-09-19 14:11:29
【问题描述】:

我们正在将旧应用迁移到 .NET MVC,并且必须保持旧 URL 的向后兼容性。考虑一个 URL 如下所示的论坛应用程序

http://example.com/forums?page=ForumsList - shows a list of all forums
http://example.com/forums?page=Threads&forumId=1 - shows list of threads in forum 1
http://example.com/forums?page=Posts&forumId=1&threadId=1 - shows posts in forum 1, thread 1.

我想将这些相同的 URL 映射到我的控制器中的操作,即

public ActionResult ForumsList(){}
public ActionResult Threads(string forumId){}
public ActionResult Posts(string forumId, string threadId){}

无需重复我们在旧系统中的维护噩梦

public ActionResult Index(string page){
    if (page == "Forums"){
         return Forums();
    }
    else if (page == "Threads){
         return Threads(Request.Params["forumId"]);
    }
    else if (page == "Posts"){
         return Posts(Request.Params["forumId"], Request.Params["threadId"]);
    }
    // oh, there's more.  a lot more.
}

我能找到的关于自定义路由的所有文档似乎都表明它只能解析 URL 的路径部分,而不是参数。我尝试了以下方法,但无济于事:

        routes.MapRoute(
            name: "TestRoutes",
            url: "{controller}/?page={action}",
            defaults: new {controller = "Forums", action = "ForumsList"});

我还能做什么?

【问题讨论】:

  • 您是否查看过 IIS 重写模块,它会拦截请求并在它们到达 asp.net 处理程序并路由到适当的控制器之前将它们重写或重定向到您的新路由。它支持非常好的正则表达式模式匹配。您可以轻松地将 forums?page=Threads&forumId=1 重写为 /forums/threads/1
  • 你的示例路由是这样 routes.MapRoute( name: "TestRoutes", url: "{controller}/?page={action}", defaults: new {controller = " Forums", action = "ForumsList"}); 你试过了吗:routes.MapRoute( name: "TestRoutes", url: "{controller}/?page={action}", defaults: new {controller = "论坛", action = "{action}");

标签: c# asp.net .net asp.net-mvc asp.net-mvc-4


【解决方案1】:

其实,你不需要做任何特别的事情。默认情况下,modelbinder 将尝试将查询字符串中的任何内容作为参数附加到操作方法。您只需使用一项操作来处理/代理所有请求:

public class ForumsController : Controller
{
    public ActionResult Index(string page, int? forumId, int? threadId)
    {
        ...
    }
}

只有默认路由:

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

可以正常工作。

URL 的主要位 /forums 将匹配 ForumsController,并且将使用默认操作 Index,因为它没有在 URL 中指定。 id 参数是可选的。然后,查询字符串中的每个项目都将设置为操作的同名参数。 forumIdthreadId 参数必须是可为空的整数,以允许仅将 page 参数传递给您的 /forums?page=ForumsList URL。

虽然您可以简单地将应用程序设置为一般以这种方式工作,但我实际上建议将此特定操作保留为票据交换所。首先,我会创建一个自定义路由,因此您不必为此投入您的 Index 操作:

routes.MapRoute(
    name: "OldForums",
    url: "forums",
    defaults: new { controller = "OldForums", action = "RedirectToNewURLs" }
);

然后:

public class OldForumsController : Controller
{
    public ActionResult RedirectToNewURLs(string page, int? forumId, int? threadId)
    {
        if (page == "ForumList")
        {
            return RedirectToActionPermanent("Index", "Forums");
        }

        if (page == "Threads")
        {
            return RedirectToActionPermanent("Threads", "Forums", { id = forumId });
        }

        // etc
    }
}

这些重定向将指向您的新论坛 URL,例如 /forums/{id}/threads。因此,如果用户通过旧 URL 进入,他们只会被重定向到新版本,而所有新用户都会从一开始就被发送到正确的 URL。

编辑

实际上,我忘了指出,这种方法的一个复杂之处在于,您实际上不能将 URL /forums 用于您的实际论坛索引。您可以使用 /forums/all 之类的东西来区分,或者只是做一些类似单数化的事情,即forum。所有其他路由都可以与 forums 前缀一起正常工作,因为只有该字符串本身会与自定义路由匹配。例如,forums/1 之类的东西会落入默认路由。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    • 2020-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多