单击routelink url不会将所有数据传递给操作

时间:2018-02-05 14:27:02

标签: c# asp.net-mvc url-routing asp.net-mvc-routing routelink

我使用RouteLink创建了网址。

@Html.RouteLink("Edit", "PageWithId",
new
{
    controller = "Customers",
    action = "Edit",
    id = item.CustomerID,
    page = ViewBag.CurrentPage
}) 

我正在使用此路由 PageWithId 与路由链接

routes.MapRoute(
    name: "PageWithId",
    url: "{controller}/{action}/{page}/{id}",
    defaults: new { controller = "Customers", action = "Edit", page = UrlParameter.Optional, id = UrlParameter.Optional }
);

我有3个路由代码。这是全部

routes.MapRoute(
    name: "PageWithSort",
    url: "{controller}/{action}/{page}/{SortColumn}/{CurrentSort}",
    defaults: new { action = "Index", page = UrlParameter.Optional, SortColumn = UrlParameter.Optional, CurrentSort = UrlParameter.Optional }
);

routes.MapRoute(
    name: "PageWithId",
    url: "{controller}/{action}/{page}/{id}",
    defaults: new { controller = "Customers", action = "Edit", page = UrlParameter.Optional, id = UrlParameter.Optional }
);

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

当我运行程序时,路径链接会生成http://localhost:55831/Customers/Edit/1/ALFKI

之类的网址

当我点击链接时,系统会调用“编辑”操作,但客户ID正在null,其中 ALFKI 在网址中作为客户ID。

以下是我的编辑操作详情

public ActionResult Edit(string id, int page)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Customer customer = db.Customers.Find(id);
    if (customer == null)
    {
        return HttpNotFound();
    }
    ViewBag.CurrentPage = page;
    return View(customer);
}

请告诉我为什么当 ALFKI 作为客户ID传递时,ID为空?

2 个答案:

答案 0 :(得分:1)

占位符(例如{page}{controller})就像一个变量。它可以匹配任何并将其存储在具有相同名称的路由值中。

所以,你实际上对你的配置说的是:

<强>尝试

/<anything (optional)>/<anything (optional)>/<anything (optional)>/<anything (optional)>/<anything (optional)>

如果不起作用,请尝试

/<anything (optional)>/<anything (optional)>/<anything (optional)>/<anything (optional)>

如果不起作用,请尝试

/<anything (optional)>/<anything (optional)>/<anything (optional)>

如果这不起作用,因为{id}是可选的,请尝试

/<anything (optional)>/<anything (optional)>

如果这不起作用,因为{action}是可选的,请尝试

/<anything (optional)> (if it matches, action will be "Index")

如果这不起作用,因为{controller}是可选的,请尝试

/ (if it matches, controller will be "Home" and action will be "Index")

看到问题?第一条路线可以(并且将)匹配任何值的URL和0到5段的任何长度。一旦匹配,就无法尝试其后的其他路线。

您需要以某种方式约束路由,以确保某些URL可以传递到下一个尝试路由,即在您不想匹配该URL的情况下。

此外,细分可以可选,但无法更改位置。如果您传递的值为CurrentSort,则自动表示其左侧的所有参数均为 required

对我来说,{page}{SortColumn}{CurrentSort}可选是不合逻辑的。如果您不需要它们,则使用不同的路由或将它们完全从路径中取出并使用查询字符串(路由不受查询字符串值的影响,它们仅在路径上匹配)。

要制作所需的值,请从默认值中删除value = UrlParameter.Optional。实际上,您可以删除所有默认值,因为控制器和操作已经在URL中传递。

routes.MapRoute(
    name: "PageWithSort",
    url: "{controller}/{action}/{page}/{SortColumn}/{CurrentSort}"
);

routes.MapRoute(
    name: "PageWithId",
    url: "{controller}/{action}/{page}/{id}"
);

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

虽然这些路线仍然可以匹配任何,但这会将它们限制为特定长度,因为它们中的所有3个具有不同数量的段,所以它们不会发生冲突。但由于它们仍然如此广泛,您应该考虑使用another technique to constrain them,例如文字段或路径约束。例如:

routes.MapRoute(
    name: "CustomerEditWithId",
    url: "Customers/Edit/{page}/{id}",
    defaults: new { controller = "Customers", action = "Edit" }
);

答案 1 :(得分:0)

应用第一条路线PageWithSort而不是第二条路线。

请注意,路由框架不知道您用于生成URL的参数名称。它只是查看收到的字符串Customers/Edit/1/ALFKI

对于此字符串,第一个路径“PageWithSort”与

匹配
  • controller = Customers
  • action =编辑
  • page = 1
  • SortColumn = ALFKI
  • CurrentSort = null(这是可以的,因为它是可选的)

因为将使用第一个匹配的路由,所以此URL永远不会达到“PageWithId”路由。

也许您可以要求“PageWithSort”的SortColumnCurrentSort参数?

或更改路线的定义顺序。

或者为“PageWithSort”路线添加一些独特的东西,例如

routes.MapRoute(
        name: "PageWithId",
        url: "{controller}/{action}/{page}/ID/{id}",
        //                                 ^^
        defaults: new { controller = "Customers", action = "Edit", page = UrlParameter.Optional, id = UrlParameter.Optional }
    );

/ID添加为URL的硬编码部分将使其与其他路由区分开(假设没有SortColumn调用“ID”)。