Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Url.Action generates query instead of parameter URL

This is the controller class. I am showing only method signatures.

[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);
}

The problem is that calling

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

returns

/specifications?subcategoryID=15

instead of

/specifications/15

Why is this happening? I do not have any similar methods on that route expect this one!

like image 383
Robert Avatar asked Oct 18 '22 18:10

Robert


1 Answers

Your call to generate the URL is incorrect. To match the controller name, it should be "specification" not "specifications".

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

Keep in mind, the URL specified in the [Route] attribute is only cosmetic. Your route values must match the controller name and action method name for it to utilize that route to generate the URL.

To make this more clear for those maintaining the code (and slightly faster), it might be better to make the parameter values Pascal case just like the controller and action names.

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

Why is this happening?

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

To get a route match, all parameters of @Url.Action must match the route value dictionary. The problem is that Controller=Specifications is not defined in the route value dictionary because your actual controller's name is SpecificationController. Therefore, the route value name is Specification regardless of what you put in the [Route] attribute. The URL ~/specifications/{subcategoryID?} has nothing at all to do with an outgoing (URL generation) match - it only matches incoming URLs and determines what the URL will look like when it is generated.

If you want to use Specifications instead of Specification for the route value, you need to move the action method to a new controller named SpecificationsController. That said, I don't see what difference it makes, since the end user won't see the route value name anyway.

like image 115
NightOwl888 Avatar answered Oct 25 '22 23:10

NightOwl888