14
votes

I cannot get @Url.Action to resolve to the url I am expecting based on the attribute route I have applied:

My action (SearchController but with [RoutePrefix("add")])

     [Route("{searchTerm}/page/{page?}", Name = "NamedSearch")]
     [Route("~/add")]
     public ActionResult Index(string searchTerm = "", int page = 1)
     {
       ...
     }

Call to Url.Action

@Url.Action("Index", new { controller = "Search", searchTerm = "replaceMe", page = 1 })

This results in a url of

/add?searchTerm=replaceMe&page=1

I would expect

/add/replaceMe/page/1

If I type the url manually then it resolves to the correct action with the correct parameters. Why doesn't @Url.Action resolve the correct url?

3

3 Answers

19
votes

Since you have a name for your pretty route definition, you may use the RouteUrl method.

@Url.RouteUrl("NamedSearch", new {  searchTerm = "replaceMe", page = 1})

And since you need add in the url, you should update your route definition to include that in the url pattern.

[Route("~/add")]
[Route("~/add/{searchTerm?}/page/{page?}", Name = "NamedSearch")]
public ActionResult Index(string searchTerm = "", int page = 1)
{
 // to do : return something
}
4
votes

Routes are order sensitive. However, attributes are not. In fact, when using 2 Route attributes on a single action like this you may find that it works on some compiles and not on others because Reflection does not guarantee an order when analyzing custom attributes.

To ensure your routes are entered into the route table in the correct order, you need to add the Order property to each attribute.

[Route("{searchTerm}/page/{page?}", Name = "NamedSearch", Order = 1)]
[Route("~/add", Order = 2)]
public ActionResult Index(string searchTerm = "", int page = 1)
{
    return View();
}

After you fix the ordering problem, the URL resolves the way you expect.

@Url.Action("Index", new { controller = "Search", searchTerm = "replaceMe", page = 1 })

// Returns "/add/replaceMe/page/1"
0
votes

To return full URL use this

@Url.Action("Index", new { controller = "Search", searchTerm = "replaceMe", page = 1}, protocol: Request.Url.Scheme)

// Returns "http://yourdomain.com/add/replaceMe/page/1"

Hope this helps someone.