【问题标题】:Url.Action generates query instead of parameter URLUrl.Action 生成查询而不是参数 URL
【发布时间】:2017-01-23 20:46:19
【问题描述】:

这是控制器类。我只显示方法签名。

[Authorize]
[RoutePrefix("specification")]
[Route("{action=index}")]
public class SpecificationController : BaseController
{
    [HttpGet]
    [Route("~/specifications/{subcategoryID?}")]
    public ActionResult Index(int? subcategoryID);

    [HttpPost]
    [Route("get/{subcategoryID?}")]
    public JsonResult Get(int? subcategoryID);

    [HttpGet]
    [Route("~/specifications/reorder/{subcategoryID}")]
    public ActionResult Reorder(int subcategoryID);

    [HttpGet]
    [Route("new/{id?}")]
    public ActionResult New(int? id);

    [HttpGet]
    [Route("edit/{id?}")]
    public ActionResult Edit(int id);

    [HttpPost]
    [ValidateAntiForgeryToken]
    [Route("edit")]
    public JsonResult Edit(SpecificationJson specification);

    [HttpPost]
    [Route("moveup")]
    public JsonResult MoveUp(int specificationID);

    [HttpPost]
    [Route("movedown")]
    public JsonResult MoveDown(int specificationID);

    [HttpDelete]
    [Route]
    public ActionResult Delete(int id);
}

问题是调用

@Url.Action("index", "specifications", new RouteValueDictionary() { { "subcategoryID", @subcategory.SubcategoryID } })

返回

/specifications?subcategoryID=15

而不是

/规范/15

为什么会这样?我在那条路线上没有任何类似的方法,除了这个!

【问题讨论】:

    标签: asp.net-mvc attributerouting


    【解决方案1】:

    您生成 URL 的调用不正确。为了匹配控制器名称,它应该是“规范”而不是“规范”。

    @Url.Action("index", "specification", new { subcategoryID=subcategory.SubcategoryID })
    

    请记住,[Route] 属性中指定的 URL 只是装饰性的。您的路由值必须与控制器名称和操作方法名称匹配,才能利用该路由生成 URL。

    为了让那些维护代码的人更清楚(并且稍微快一点),最好将参数值设为 Pascal 大小写,就像控制器和操作名称一样。

    @Url.Action("Index", "Specification", new { subcategoryID=subcategory.SubcategoryID })
    

    为什么会这样?

    -------------------------------------------------------------
    | Route Key          | Route Value   | Your Action Request  |
    |--------------------|---------------|----------------------|
    | Controller         | Specification | Specifications       | No Match
    | Action             | Index         | Index                | Match
    | subcategoryID      | ?             | XXX                  | Match (Always)
    -------------------------------------------------------------
    

    要获得路由匹配,@Url.Action 的所有参数必须与路由值字典匹配。问题是Controller=Specifications 没有在路由值字典中定义,因为您的实际控制器的名称SpecificationController。因此,无论您在[Route] 属性中添加了什么,路由值名称都是Specification。 URL ~/specifications/{subcategoryID?} 与传出(URL 生成)匹配完全没有关系 - 它只匹配传入的 URL 并确定生成 URL 时的样子。

    如果你想使用Specifications而不是Specification作为路由值,你需要将action方法移动到一个名为SpecificationsController的新控制器。也就是说,我看不出它有什么不同,因为最终用户无论如何都不会看到路由值名称。

    【讨论】:

    • 我知道,如果我按照你说的那样做,它就会起作用。以前是这样的。为了更加一致,我决定当我返回所有结果的视图时,它应该说 /specifications 而不是 /specification,因为后者意味着它只是我们正在谈论的一个规范。此外,我认为通过在路由属性中使用 ~/specifications,我清楚地表明我正在重新启动路由,而不是使用控制器中指定的路由前缀。
    • 是的,但是为了让它工作,你必须将动作方法移动到一个名为SpecificationsController的控制器。如果没有正确指定它,您将获得一条路线未命中并且它正在匹配另一条路线,这就是您获得查询字符串的原因。
    • 这就像一个魅力。我认为重写路线会完全重新定义它。看来你是对的!
    【解决方案2】:

    您必须使用它来生成关注网址:/specifications/15

    @Url.Action("index", "specifications", new { subcategoryID=subcategory.SubcategoryID })
    
    [Route("~/specifications/{subcategoryID?}")]
    public ActionResult Index(int? subcategoryID);
    

    我做错了什么以及如何恢复使用 subcategoryID 作为 参数名称?

    您必须添加另一个路由(在 DEFAULT ROUTE 之前)才能有另一个 optional 参数:

    类似这样的:

     routes.MapRoute(
             "SecondRoute",
             "{controller}/{action}/{subcategoryID}",
              defaults: new { controller = "Home", action = "Index", subcategoryID = UrlParameter.Optional }
     );
    

    【讨论】:

    • 为什么是id 而不是subcategoryID
    • 你收到相同的结果吗?
    • @Alexandru-IonutMihai 是的。
    • 好的,这行得通。但为什么?我做错了什么以及如何恢复使用 subcategoryID 作为参数名称。
    • @Rob,请看我的回答。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多