Ad

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

www.abc.com/Fashion/ProductDetail?productId=5088&productName=AliviaBlack&brandId=3

Requirement are

www.abc.com/alivia-black 

I have tried following by using attribute routing

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

In view page

 <a asp-route-productId="@product.ProductId"
                       asp-route-productName="@Common.FilterURL(product.ProductName)"
                       asp-route-brandId="@product.FashionBrand.FashionBrandId" asp-route="SpecificRoute">

Result is

www.abc.com/alivia-black?productId=5223&brandId=4

How to remove question mark and parameters after it.

Ad

Answer

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

www.abc.com/alivia-black

i.e.:

{host}/{productName}

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.

https://stackoverflow.com/questions/69748993/how-to-show-seo-friendly-url-in-mvc-core-3-1

https://stackoverflow.com/questions/69748993

I strongly recommend you read this article on the W3.org'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:

{host}/products/{productId}/{productName}

Which will give you a URI like this:

abc.com/products/5088/alivablack

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>
Ad
source: stackoverflow.com
Ad