How To Show Seo Friendly Url In Mvc Core 3.1?

I am working on a mvc core 3.1 application. Seo requirements are to show product name with main site instead of complete url.

My original url is

Requirement are 

I have tried following by using attribute routing

           name: "SpecificRoute",
           pattern: "/{productName}",
           defaults: new { controller = "Fashion", action = "ProductDetail", id= "{productId}" });

In view page

 <a asp-route-productId="@product.ProductId"
                       asp-route-brandId="@product.FashionBrand.FashionBrandId" asp-route="SpecificRoute">

Result is

How to remove question mark and parameters after it.



First off, URIs need to be resilient. You say your current requirement is to have URIs like this:



That's a very bad URI template because:

  • It does not uniquely identify the product (as you could have multiple products with the same name).
  • It will break existing links from external websites if you ever rename a product or replace a product with the same name. And this happens a lot in any product database.
  • Because you're putting the {productName} in the "root" of your URI structure it means it's much harder to handle anything else besides viewing products (e.g. how would you have a /contact-us page? What if you had a product that was named contact-us?)

I stress that is is very important to include an immutable key to the entity being requested (in this case, your productId value) in the URI and use that as a primary-reference, so the productName can be ignored when handling an incoming HTTP request. This is how StackOverflow's and Amazon's URIs work (you can trim off the text after a StackOverflow's question-id and it will still work: e.g.

I strongly recommend you read this article on the's website all about designing good URIs, as well as other guidance from that group's homepage.

I suggest you use a much better URI template, such as this one:


Which will give you a URI like this:

Handling such a link in ASP.NET MVC (and ASP.NET Core) is trivial, just set the route-template on your controller action:

[Route( "/products/{productId:int}/{productName?}" )]
public async Task<IActionResult> ShowProduct( Int32 productId, String? productName = null )
    // Use `productId` to lookup the product.
    // Disregard `productName` unless you want to use it as a fallback to search your database if `productId` doesn't work.

As for generating URIs, as I recommend against using TagHelpers (e.g. <a asp-route-) because they don't give you sufficient control over how the URI is rendered, instead you can define a UrlHelper extension method (ensure you @import the namespace into your .cshtml pages (or add it to ViewStart):

public static class MyUrls
    public static String ShowProduct( this IUrlHelper u, Int32 productId, String productName )
        const String ACTION_NAME = nameof(ProductsController.ShowProduct);
        const String CONTROLLER_NAME = "Products"; // Unfortunately we can't use `nameof` here due to the "Controller" suffix in the type-name.

        String url = u.Action( action: ACTION_NAME, controller: CONTROLLER_NAME, values: new { productId = productId, productName = productName } );
        return url;

Then you can use it like so:

<a href="@Urls.ShowProduct( 5088, "aliviablack" )">View AliviaBlack</a>

You can also make ShowProduct accept one of your Product objects directly and then pass the values on to the other overload (defined above) which accepts scalars:

    public static String ShowProduct( this IUrlHelper u, Product product )
        String url = ShowProduct( u, productId: product.ProductId, productName: product.ProductName );
        return url;

Then you can use it like so (assuming product is in-scope):

<a href="@Urls.ShowProduct( product )">@product.ProductName</a>