ASP.NET MVC路由-Url.Action发送查询字符串而不是路由值 路由模板路线名称可能的错误

问题描述

几天来我一直在寻找解决这个问题的方法,但是我很沮丧。

我有一个ASP.NET MVC应用程序,其中已实现了分页,排序和筛选。在第一个视图中它运行良好,然后在下一个视图中实现它时,它停止了工作。我正在遵循this指南。

在进行更改之前,如果使用过滤器,它将回发并执行正确的操作并过滤结果。单击底部的页码之一,将带我进入过滤后的结果集中的页面。

更改后,我遇到一个错误,因为与多个匹配的路由发生冲突。由于这两个控制器的路由值都相同,因此我认为我需要将控制器名称添加为路由的第一部分。

现在,当我应用过滤器时,它仍然可以工作,但是在单击另一个页码后,将删除过滤器,但会得到正确的页码(在未过滤的结果集上)。调试显示,它将转到默认的Index操作,而不是将应用过滤和排序的已定义路由。

区别在于,在更改之前,它发送的是以下网址:

https://localhost:44382/Users/Index/UserName/ascending/none/all/2/an

现在正在发送:

https://localhost:44382/Users/Index?sortKey=UserName&sortDirection=ascending&previousSortKey=none&selectedFbSupplied=all&page=2&selectedNameFilter=an

如果我手动将其更改为路由值,而不是使其按预期工作的查询字符串。

下面的代码的相关部分。

来自UsersController:

    [HttpGet]
    [Route("Users/Index")]
    public ActionResult Index(int? page)
    {
        ViewBag.SortKey = "UserName";
        ViewBag.SortDirection = "ascending";
        ViewBag.SelectedFbSupplied = string.IsNullOrEmpty(ViewBag.SelectedFbSupplied) ? "all" : ViewBag.SelectedFbSupplied;
        ViewBag.SelectedNameFilter = string.IsNullOrEmpty(ViewBag.SelectedNameFilter) ? "" : ViewBag.SelectedNameFilter;

        ViewBag.FbSupplied = new List<SelectListItem>{
                                                       new SelectListItem { Value="all",Text="All"},new SelectListItem { Value="yes",Text="Yes"},new SelectListItem { Value="no",Text="No"}
                                                    };

        var users = SortedUserList(FilteredUsers());
        int pageSize = 50;
        int pageNumber = (page ?? 1);
        return View(users.ToPagedList(pageNumber,pageSize));
    }

    [HttpGet]
    [Route("Users/Index/{sortKey}/{sortDirection}/{previousSortKey}/{selectedFbSupplied}/{page:int}/{selectedNameFilter?}")]
    public ActionResult Index(string sortKey,string sortDirection,string previousSortKey,string selectedFbSupplied,int? page,string selectedNameFilter="")
    {
                    
        if (sortKey == previousSortKey)
        {
            //Key is the same,flip the direction
            sortDirection = sortDirection == "ascending" ? "descending" : "ascending";
        }
        ViewBag.SortKey = String.IsNullOrEmpty(sortKey) ? "UserName" : sortKey;
        ViewBag.SortDirection = String.IsNullOrEmpty(sortDirection) ? "ascending" : sortDirection;


        ViewBag.FbSupplied = new List<SelectListItem>{
                                                       new SelectListItem { Value="all",Text="No"}
                                                    };

        var nameFilter = string.IsNullOrEmpty(selectedNameFilter) ? "" : selectedNameFilter;
        ViewBag.SelectedFbSupplied = string.IsNullOrEmpty(selectedFbSupplied) ? "all" : selectedFbSupplied;
        ViewBag.SelectedNameFilter = nameFilter;


        var users = SortedUserList(FilteredUsers(nameFilter,selectedFbSupplied),sortKey,sortDirection);
        int pageSize = 50;
        int pageNumber = (page ?? 1);
        return View(users.ToPagedList(pageNumber,pageSize));
    }

页面在视图中链接:

@Html.PagedListPager(Model,page => Url.Action("Index","Users",new { sortKey = ViewBag.SortKey,sortDirection = ViewBag.SortDirection,previousSortKey = "none",selectedFbSupplied = ViewBag.SelectedFbSupplied,page = page,selectedNameFilter = ViewBag.SelectedNameFilter}))

路由配置(不变):

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.MapMvcAttributeRoutes();

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

}

有什么想法为什么要发送查询字符串而不是路由值?

解决方法

简而言之:如果您指定路由名称(而不仅仅是路由模板),则可以通过RouteUrl帮助程序通过其名称来引用它们。

路由模板

  • 这是一种模式,它定义了如何实现给定的动作以及如何匹配路由参数。
  • 它们被注册到RouteTable中,该路由表基本上是给定的url模式与关联的控制器的操作之间的映射。
  • 路线的顺序很重要,因为第一个匹配项获胜。

路线名称

  • 它们与网址模式匹配无关。
  • 它们仅在生成网址时使用。 ({RouteUrlCreatedAtRoute1)等)
  • 它们必须是全局唯一的(因此顺序无关紧要)。

可能的错误

  • 如果您使用相同的Template注册两条路由,那么当您对其中一条路由进行呼叫时,应用程序将在运行时抛出AmbiguousMatchException
    • 因此,其他路线也可以正常工作。
  • 如果您使用相同的Name注册两条路由,那么当您进行 any 调用时,应用程序将在运行时抛出InvalidOperationException
    • 因此,其他路线将无效。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...