ASP.NET Core Attribute Routing - Locale Prefix

Viewed 163

I have the following controller:

[Route("blog")]
[Route("{locale:regex(^(de|es|fr)$)}/blog", Order = -1)]
public class BlogController : Controller {
    [HttpGet("{id:int}.htm")]
    [HttpGet("{slug}/{id:int}.htm")]
    public IActionResult Details(string? slug, int id) {
        return View();
    }
}

Now if I try to generate the following URLs:

  • @Url.Action("Details", "Blog", new { id = 1 })
  • @Url.Action("Details", "Blog", new { slug = "cat-1", id = 1 })
  • @Url.Action("Details", "Blog", new { id = 1, locale = "fr" })
  • @Url.Action("Details", "Blog", new { slug = "cat-1", id = 1, locale = "fr" })

I would expect the following:

  • /blog/1.htm
  • /blog/cat-1/1.htm
  • /fr/blog/1.htm
  • /fr/blog/cat-1/1.htm

However this returns:

  • /blog/1.htm
  • /blog/1.htm?slug=cat-1
  • /fr/blog/1.htm
  • /fr/blog/1.htm?slug=cat-1

I have tried changing the order on all the routing attributes but I cannot get it to return the desired result and I’d appreciate any help.

2 Answers

The following example gives the intended results:

public class BlogController : Controller
{
    [Route("{locale:regex(^(de|es|fr)$)}/blog/{slug}/{id:int}.htm")]
    [Route("{locale:regex(^(de|es|fr)$)}/blog/{id:int}.htm", Order = 1)]
    [Route("blog/{slug}/{id:int}.htm", Order = 2)]
    [Route("blog/{id:int}.htm", Order = 3)]
    public IActionResult Details(string? slug, int id)
    {
        return View();
    }
}

This approach uses an earlier Order for more specific routes, so that those are checked first. The obvious downside is the verbosity, but it's a working solution based on the requirements described.

If you don't mind changing the order of slug,you can change the controller like following:

    [Route("blog")]
    [Route("{locale:regex(^(de|es|fr)$)}/blog", Order = -1)]
    public class BlogController : Controller
    {
        [HttpGet("{id:int}.htm/{slug?}")]
        public IActionResult Details(string? slug, int id)
        {
            return View();
        }
    }

Generate the following URLs:

@Url.Action("Details", "Blog", new { id = 1 })
@Url.Action("Details", "Blog", new { slug = "cat-1", id = 1 })
@Url.Action("Details", "Blog", new { id = 1, locale = "fr" })
@Url.Action("Details", "Blog", new { slug = "cat-1", id = 1, locale = "fr" })

Result:

/blog/1.htm
/blog/1.htm/cat-1
/fr/blog/1.htm
/fr/blog/1.htm/cat-1
Related