---
title: "SEO Friendly URL's for ASP.NET Core - Muhammad Rehan Saeed"
description: "An SEO friendly URL is human readable and gives your site a higher page rank. Learn how to implement SEO friendly URL's using ASP.NET Core."
canonical_url: "https://rehansaeed.com/seo-friendly-urls-asp-net-core/"
last_updated: "2016-12-17T00:00:00+00:00"
meta:
  author: "Muhammad Rehan Saeed"
  keywords: ".NET,ASP.NET Core,ASP.NET MVC,.NET Boxed,Friendly URL,Search Engine Optimization (SEO)"
  "og:description": "An SEO friendly URL is human readable and gives your site a higher page rank. Learn how to implement SEO friendly URL's using ASP.NET Core."
  "og:image": "https://rehansaeed.com/_og/s/o_19969a442729ed21.png"
  "og:image:alt": "SEO Friendly URL's for ASP.NET Core - Muhammad Rehan Saeed"
  "og:image:height": "630"
  "og:image:type": image/png
  "og:image:width": "1200"
  "og:title": "SEO Friendly URL's for ASP.NET Core"
  "twitter:image": "https://rehansaeed.com/_og/s/o_19969a442729ed21.png"
  "twitter:image:alt": "SEO Friendly URL's for ASP.NET Core - Muhammad Rehan Saeed"
---

> Index of every page on this site: [llms.txt](https://rehansaeed.com/llms.txt)

# [SEO Friendly URL's for ASP.NET Core](https://rehansaeed.com/seo-friendly-urls-asp-net-core/)

Posted 17 December 2016 - **7 min read**

![Search Engine-Optimization-SEO](https://rehansaeed.com/_ipx/f_webp&s_2560x1440/images/hero/Search-Engine-Optimization-SEO-1366x768.png)

For some reason there are not a lot of Search Engine Optimization (SEO) blog posts or projects out there. Taking a few simple steps can make your site rank higher in Google or Bing search results so it's well worth doing. Here are a few other of my SEO related blog posts:

- [Canonical URL's for ASP.NET MVC](https://rehansaeed.com/canonical-urls-for-asp-net-mvc/)
- [Dynamically Generating Sitemap.xml for ASP.NET MVC](https://rehansaeed.com/dynamically-generating-sitemap-xml-for-asp-net-mvc/)
- [Dynamically Generating Robots.txt Using ASP.NET MVC](https://rehansaeed.com/dynamically-generating-robots-txt-using-asp-net-mvc/)

# What is an SEO Friendly URL?

This Mozilla blog post called ' [15 best practices for structuring URL's'](https://moz.com/blog/15-seo-best-practices-for-structuring-urls) is the best article on the subject of SEO friendly URL's I found and it's well worth a read.

Essentially you want a simple short URL that tells the user what they are clicking on at a glance. It should also contain keywords pertaining to what is on the page for better Search Engine Optimization (SEO). In short, a page will appear higher up in search results if the term a user searches for appears in the URL. Your URL should look like this:

![SEO Friendly URL Example](https://rehansaeed.com/_ipx/s_2560x268/content-images/posts/2016/seo-friendly-urls-asp-net-core/images/SEO-Friendly-URL.png)

The URL contains an ID for a product and ends with a friendly title. The title contains alphanumeric characters with dashes instead of spaces. Note that the ID of the product is still included in the URL, to avoid having to deal with two friendly titles with the same name.

If you elect to omit the ID, then you have to do a lot of footwork to make things work. Firstly, you have to use the title as a kind of primary key to get the product data from your database and secondly, you also have to figure out what to do when there are two pages with the same title. Each time you want to create a new title, you have to scan your data store to see if the title already exists and if it does either error and force the creation of a different title or add make it unique by adding a number on the end. This is a lot of work but does produce a nicer URL, the choice is yours.

# How to Build One

Take a look at the controller action below. It is a very simple example of how to use SEO friendly URL's. In our example we have a product class which has a ID and title properties, where the title is just the name of the product.

```cs
[HttpGet("product/{id}/{title}", Name = "GetProduct")]
public IActionResult GetProduct(int id, string title)
{
    // Get the product as indicated by the ID from a database or some repository.
    var product = this.productRepository.Find(id);

    // If a product with the specified ID was not found, return a 404 Not Found response.
    if (product == null)
    {
        return this.NotFound();
    }

    // Get the actual friendly version of the title.
    string friendlyTitle = FriendlyUrlHelper.GetFriendlyTitle(product.Title);

    // Compare the title with the friendly title.
    if (!string.Equals(friendlyTitle, title, StringComparison.Ordinal))
    {
        // If the title is null, empty or does not match the friendly title, return a 301 Permanent
        // Redirect to the correct friendly URL.
        return this.RedirectToRoutePermanent("GetProduct", new { id = id, title = friendlyTitle });
    }

    // The URL the client has browsed to is correct, show them the view containing the product.
    return this.View(product);
}
```

All the work is done by the `FriendlyUrlHelper` which turns the product title which may contain spaces, numbers or other special characters (which would not be allowed in a URL without escaping them) into a `lower-kebab-case` title.

This generated friendly title is compared with the one that is passed in and if it is different (Someone may have omitted the friendly title or mis-spelled it) we perform a permanent redirect to the product with the same ID but now with the friendly title. This is important for SEO purposes, we want search engines to only find one URL for each product. Finally, if the friendly title matches the one passed in we return the product view.

# The FriendlyUrlHelper

The `FriendlyUrlHelper` was inspired by a famous Stack Overflow question ' [How does Stack Overflow generate its SEO-friendly URLs?](https://stackoverflow.com/questions/25259/how-does-stack-overflow-generate-its-seo-friendly-urls/25486)'. The full source code for it is shown below.

```cs
/// <summary>
/// Helps convert <see cref="string"/> title text to URL friendly <see cref="string"/>'s that can safely be
/// displayed in a URL.
/// </summary>
public static class FriendlyUrlHelper
{
    /// <summary>
    /// Converts the specified title so that it is more human and search engine readable e.g.
    /// http://example.com/product/123/this-is-the-seo-and-human-friendly-product-title. Note that the ID of the
    /// product is still included in the URL, to avoid having to deal with two titles with the same name. Search
    /// Engine Optimization (SEO) friendly URL's gives your site a boost in search rankings by including keywords
    /// in your URL's. They are also easier to read by users and can give them an indication of what they are
    /// clicking on when they look at a URL. Refer to the code example below to see how this helper can be used.
    /// Go to definition on this method to see a code example. To learn more about friendly URL's see
    /// https://moz.com/blog/15-seo-best-practices-for-structuring-urls.
    /// To learn more about how this was implemented see
    /// http://stackoverflow.com/questions/25259/how-does-stack-overflow-generate-its-seo-friendly-urls/25486#25486
    /// </summary>
    /// <param name="title">The title of the URL.</param>
    /// <param name="remapToAscii">if set to <c>true</c>, remaps special UTF8 characters like 'è' to their ASCII
    /// equivalent 'e'. All modern browsers except Internet Explorer display the 'è' correctly. Older browsers and
    /// Internet Explorer percent encode these international characters so they are displayed as'%C3%A8'. What you
    /// set this to depends on whether your target users are English speakers or not.</param>
    /// <param name="maxlength">The maximum allowed length of the title.</param>
    /// <returns>The SEO and human friendly title.</returns>
    /// <code>
    /// [HttpGet("product/{id}/{title}", Name = "GetDetails")]
    /// public IActionResult Product(int id, string title)
    /// {
    ///     // Get the product as indicated by the ID from a database or some repository.
    ///     var product = ProductRepository.Find(id);
    ///
    ///     // If a product with the specified ID was not found, return a 404 Not Found response.
    ///     if (product == null)
    ///     {
    ///         return this.HttpNotFound();
    ///     }
    ///
    ///     // Get the actual friendly version of the title.
    ///     var friendlyTitle = FriendlyUrlHelper.GetFriendlyTitle(product.Title);
    ///
    ///     // Compare the title with the friendly title.
    ///     if (!string.Equals(friendlyTitle, title, StringComparison.Ordinal))
    ///     {
    ///         // If the title is null, empty or does not match the friendly title, return a 301 Permanent
    ///         // Redirect to the correct friendly URL.
    ///         return this.RedirectToRoutePermanent("GetProduct", new { id = id, title = friendlyTitle });
    ///     }
    ///
    ///     // The URL the client has browsed to is correct, show them the view containing the product.
    ///     return this.View(product);
    /// }
    /// </code>
    public static string GetFriendlyTitle(string title, bool remapToAscii = false, int maxlength = 80)
    {
        if (title == null)
        {
            return string.Empty;
        }

        int length = title.Length;
        bool prevdash = false;
        StringBuilder stringBuilder = new StringBuilder(length);
        char c;

        for (int i = 0; i < length; ++i)
        {
            c = title[i];
            if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9'))
            {
                stringBuilder.Append(c);
                prevdash = false;
            }
            else if (c >= 'A' && c <= 'Z')
            {
                // tricky way to convert to lower-case
                stringBuilder.Append((char)(c | 32));
                prevdash = false;
            }
            else if ((c == ' ') || (c == ',') || (c == '.') || (c == '/') ||
                (c == '\\') || (c == '-') || (c == '_') || (c == '='))
            {
                if (!prevdash && (stringBuilder.Length > 0))
                {
                    stringBuilder.Append('-');
                    prevdash = true;
                }
            }
            else if (c >= 128)
            {
                int previousLength = stringBuilder.Length;

                if (remapToAscii)
                {
                    stringBuilder.Append(RemapInternationalCharToAscii(c));
                }
                else
                {
                    stringBuilder.Append(c);
                }

                if (previousLength != stringBuilder.Length)
                {
                    prevdash = false;
                }
            }

            if (i == maxlength)
            {
                break;
            }
        }

        if (prevdash)
        {
            return stringBuilder.ToString().Substring(0, stringBuilder.Length - 1);
        }
        else
        {
            return stringBuilder.ToString();
        }
    }

    /// <summary>
    /// Remaps the international character to their equivalent ASCII characters. See
    /// http://meta.stackexchange.com/questions/7435/non-us-ascii-characters-dropped-from-full-profile-url/7696#7696
    /// </summary>
    /// <param name="character">The character to remap to its ASCII equivalent.</param>
    /// <returns>The remapped character</returns>
    private static string RemapInternationalCharToAscii(char character)
    {
        string s = character.ToString().ToLowerInvariant();
        if ("àåáâäãåąā".Contains(s))
        {
            return "a";
        }
        else if ("èéêëę".Contains(s))
        {
            return "e";
        }
        else if ("ìíîïı".Contains(s))
        {
            return "i";
        }
        else if ("òóôõöøőð".Contains(s))
        {
            return "o";
        }
        else if ("ùúûüŭů".Contains(s))
        {
            return "u";
        }
        else if ("çćčĉ".Contains(s))
        {
            return "c";
        }
        else if ("żźž".Contains(s))
        {
            return "z";
        }
        else if ("śşšŝ".Contains(s))
        {
            return "s";
        }
        else if ("ñń".Contains(s))
        {
            return "n";
        }
        else if ("ýÿ".Contains(s))
        {
            return "y";
        }
        else if ("ğĝ".Contains(s))
        {
            return "g";
        }
        else if (character == 'ř')
        {
            return "r";
        }
        else if (character == 'ł')
        {
            return "l";
        }
        else if (character == 'đ')
        {
            return "d";
        }
        else if (character == 'ß')
        {
            return "ss";
        }
        else if (character == 'Þ')
        {
            return "th";
        }
        else if (character == 'ĥ')
        {
            return "h";
        }
        else if (character == 'ĵ')
        {
            return "j";
        }
        else
        {
            return string.Empty;
        }
    }
}
```

The difference between my version and the one in the Stack Overflow answer is that mine optionally handles non-ASCII characters using the boolean remapToAscii parameter. This parameter remaps special UTF8 characters like `è` to their ASCII equivalent `e`. If there is no equivalent, then those characters are dropped. All modern browsers except Internet Explorer and Edge display the `è` correctly. Older browsers like Internet Explorer percent encode these international characters so they are displayed as `%C3%A8`. What you set this to depends on whether your target users are English speakers and if you care about supporting IE and Edge. I must say that I was hoping Edge would have added support so that `remapToAscii` could be turned off by default but I'm sorely disappointed.

Using the third parameter you can specify a maximum length for the title with any additional characters being dropped. Finally, the last thing to say about this method is that it has been tuned for speed.

# Where Can I Get It?

This is a great little snippet of code to make your URL's a human readable, while giving your site an SEO boost. It doesn't take much effort to use either. This helper class is available in the [Boxed.AspNetCore](https://www.nuget.org/packages/Boxed.AspNetCore) NuGet package or you can look at the source code in the [.NET Boxed Framework](https://github.com/Dotnet-Boxed/Framework) GitHub page.

## Web Mentions

[What's this?](https://en.wikipedia.org/wiki/Webmention)

### 0 Linked

### 0 Replies

## Comment

[Leave and View Directly on GitHub.com](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113)

13 Comments

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

[RehanSaeed](https://github.com/RehanSaeed) [12 May 2020](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113#issuecomment-627274356)

[![Karim](https://camo.githubusercontent.com/ef58ad4f80aa920045a60f978d54962ce963a79dece23df722f2d54e55063246/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f38656564623562336231623166356533303766393731353637653965373035633f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/ef58ad4f80aa920045a60f978d54962ce963a79dece23df722f2d54e55063246/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f38656564623562336231623166356533303766393731353637653965373035633f733d393626643d6d6d26723d67) **Karim** commented on **2017-01-24 12:23:27**

Unfortunately you do not explain how the routing is structured. E.g. how would an anchor tag would look like in order to call the method, how the routing in the startup file is configured.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

[RehanSaeed](https://github.com/RehanSaeed) [12 May 2020](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113#issuecomment-627274403)

[![Muhammad Rehan Saeed](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67) **[Muhammad Rehan Saeed](https://rehansaeed.com/)** commented on **2017-01-25 08:59:25**

> Unfortunately you do not explain how the routing is structured. E.g. how would an anchor tag would look like in order to call the method, how the routing in the startup file is configured.

The ASP.NET website has those basics covered. I assume some basic knowledge in my blog.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

[RehanSaeed](https://github.com/RehanSaeed) [12 May 2020](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113#issuecomment-627274453)

[![Chris](https://camo.githubusercontent.com/5889f885624cfe786404349bda514617653f9768ef46a9f4e16fbb94a3d95a3c/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f64633865616163396630373465666530396263323366306461386562643334613f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/5889f885624cfe786404349bda514617653f9768ef46a9f4e16fbb94a3d95a3c/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f64633865616163396630373465666530396263323366306461386562643334613f733d393626643d6d6d26723d67) **Chris** commented on **2017-02-18 12:20:47**

This is a great article, thanks a lot!

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

[RehanSaeed](https://github.com/RehanSaeed) [12 May 2020](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113#issuecomment-627274500)

[![Thomas](https://camo.githubusercontent.com/382477acb8407171f851e8743025c684b6c107a34bda3a214be2c6f5e041c23d/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f35373033366237643464653064636335633563313636313037393833373639383f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/382477acb8407171f851e8743025c684b6c107a34bda3a214be2c6f5e041c23d/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f35373033366237643464653064636335633563313636313037393833373639383f733d393626643d6d6d26723d67) **Thomas** commented on **2017-03-31 21:08:46**

Great article!

But how to handle pages that is not a product (no productId) ?  
 Also, what do you think is the best approach to combine this with multi language support (localized urls)?

Regards, Thomas

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

[RehanSaeed](https://github.com/RehanSaeed) [12 May 2020](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113#issuecomment-627274559)

[![Muhammad Rehan Saeed](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67) **[Muhammad Rehan Saeed](https://rehansaeed.com/)** commented on **2017-04-08 08:43:48**

> Great article!
>
> But how to handle pages that is not a product (no productId) ?  
>  Also, what do you think is the best approach to combine this with multi language support (localized urls)?
>
> Regards, Thomas

Having no parameters makes no difference. For localized URL's, the culture e.g. `en-GB` is part of the URL, so you end up with multiple copies in Google. I think that makes sense if the page is in a different language.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

[RehanSaeed](https://github.com/RehanSaeed) [12 May 2020](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113#issuecomment-627274609)

[![Milton](https://camo.githubusercontent.com/6472c3b771535536a8103369140ca010d1c3b979eb282b99d010a7243c43ab1b/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f39653530303633306138663361663433303435643563363366323736306261383f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/6472c3b771535536a8103369140ca010d1c3b979eb282b99d010a7243c43ab1b/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f39653530303633306138663361663433303435643563363366323736306261383f733d393626643d6d6d26723d67) **Milton** commented on **2017-04-30 05:55:07**

Is possible to use this without productId, only product name? So I have to get Id to get from database, something like `test.com.br/product/playstation-2`.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

[RehanSaeed](https://github.com/RehanSaeed) [12 May 2020](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113#issuecomment-627274650)

[![Muhammad Rehan Saeed](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67) **[Muhammad Rehan Saeed](https://rehansaeed.com/)** commented on **2017-05-05 14:34:23**

> Is possible to use this without productId, only product name? So I have to get Id to get from database, something like `test.com.br/product/playstation-2`.

Yes, it is.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

[RehanSaeed](https://github.com/RehanSaeed) [12 May 2020](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113#issuecomment-627274697)

[![Kelsey Steele](https://camo.githubusercontent.com/d13734fe0408b188fb159c8501b44e831ad264e2d3cbcad773eba2956d28ee0b/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f61303664353661346230656634316565636131613637383061653063323564663f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/d13734fe0408b188fb159c8501b44e831ad264e2d3cbcad773eba2956d28ee0b/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f61303664353661346230656634316565636131613637383061653063323564663f733d393626643d6d6d26723d67) **Kelsey Steele** commented on **2017-11-02 20:37:13**

> Unfortunately you do not explain how the routing is structured. E.g. how would an anchor tag would look like in order to call the method, how the routing in the startup file is configured.

Karim, I am having the same problem. I don't think it's that basic. I've been Googling for days but the ASP.NET website is confusing and not built for beginners. Many sources say to create a class that structures the url, but they do not say how to call the class. Any help would be greatly appreciated.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

[RehanSaeed](https://github.com/RehanSaeed) [12 May 2020](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113#issuecomment-627274740)

[![medifast coupons for 2011](https://camo.githubusercontent.com/172de3d3322fa8661e97cf6af284b16359f9d580639e8e5f5eef0055122f7eb7/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f64313137653165616432363865396430323564396661626433346432646631383f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/172de3d3322fa8661e97cf6af284b16359f9d580639e8e5f5eef0055122f7eb7/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f64313137653165616432363865396430323564396661626433346432646631383f733d393626643d6d6d26723d67) **[medifast coupons for 2011](http://mattcutts.com/)** commented on **2018-07-21 01:06:16**

Pretty! This was an extremely wonderful article. Thank you for providing these details.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

[RehanSaeed](https://github.com/RehanSaeed) [12 May 2020](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113#issuecomment-627274782)

[![Volkan](https://camo.githubusercontent.com/5302faa4d60b1722b635ab569168b9ba0bb5dc1be2eb90198025f7fd41b189fe/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f63326134356430363334373563366230616636643330383564316438376261393f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/5302faa4d60b1722b635ab569168b9ba0bb5dc1be2eb90198025f7fd41b189fe/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f63326134356430363334373563366230616636643330383564316438376261393f733d393626643d6d6d26723d67) **Volkan** commented on **2019-10-21 15:45:34**

I think `Ã°` should be replaced as `d`.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

[RehanSaeed](https://github.com/RehanSaeed) [12 May 2020](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113#issuecomment-627274839)

[![Muhammad Rehan Saeed](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/8a07049df41b8a3839a3f4342f09ea8e6e7fa0065667687f04beca2d088a1dca/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f32623266393030653361633066353535316462646537323864336262343935343f733d393626643d6d6d26723d67) **[Muhammad Rehan Saeed](https://rehansaeed.com/)** commented on **2019-11-29 17:48:16**

> I think `Ã°` should be replaced as `d`.

The idea is to replace characters that look like the English `o`.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

[RehanSaeed](https://github.com/RehanSaeed) [12 May 2020](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113#issuecomment-627274882)

[![Hamzi Alsheikh](https://camo.githubusercontent.com/5c95cae6dae0483fa57d6dec9e758ad8c53ef8a4d66545d1a5b14937d596ff57/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f36623036313836396435313336333233623839363836313063383535626232663f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/5c95cae6dae0483fa57d6dec9e758ad8c53ef8a4d66545d1a5b14937d596ff57/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f36623036313836396435313336333233623839363836313063383535626232663f733d393626643d6d6d26723d67) **[Hamzi Alsheikh](https://www.hmz-software.cf/)** commented on **2020-03-09 01:42:57**

> Karim, I am having the same problem. I don't think it's that basic. I've been Googling for days but the ASP.NET website is confusing and not built for beginners. Many sources say to create a class that structures the url, but they do not say how to call the class. Any help would be greatly appreciated.

Thank you, Rehan for this excellent post, I've always wanted to do this in asp.net core.  
 For anyone looking for how to map the route for this to work here is a simple example that uses the same convention that StackOverflow uses:

```
mvcRoutes.MapRoute(
    name: "subcategory",
    template: "{controller}/{action=Index}/{id}/{title?}", new { controller = "SubCategory"});
```

(name the route whatever you want)

```
mvcRoutes.MapRoute(
    name: "default",
    template: "{controller=Home}/{action=Index}/{id?}");
```

Notice the (action=Index) in the first route it is used to omit the action name and using the friendly name helper you get something like this: `www.domain.com/2/some-product`.

[![RehanSaeed](https://avatars.githubusercontent.com/u/2270364?v=4)](https://github.com/RehanSaeed)

[RehanSaeed](https://github.com/RehanSaeed) [12 May 2020](https://github.com/RehanSaeed/rehansaeed.github.io/issues/113#issuecomment-627274926)

[![Sunny](https://camo.githubusercontent.com/e6da559f9511ad53408761fd2a693d3916738578a1208a64eada855b758594f9/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f33623036383863353035623137323261333262303236316633323864623230653f733d393626643d6d6d26723d67)](https://camo.githubusercontent.com/e6da559f9511ad53408761fd2a693d3916738578a1208a64eada855b758594f9/68747470733a2f2f7777772e67726176617461722e636f6d2f6176617461722f33623036383863353035623137323261333262303236316633323864623230653f733d393626643d6d6d26723d67) **Sunny** commented on **2020-05-01 16:06:32**

Do you have any Idea about aasp.net boilerplate? I would like to learn something like permission management, user management etc... for a multi-tenancy website.

```json
{"@context":"https://schema.org","@graph":[{"@id":"https://rehansaeed.com/#website","@type":"WebSite","description":"Software Developer at Microsoft, YouTuber, Open Source Contributor and Blogger","inLanguage":"en-GB","name":"Muhammad Rehan Saeed","url":"https://rehansaeed.com/","author":{"@id":"https://rehansaeed.com/#identity"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://rehansaeed.com/?search={search_term_string}"},"query-input":"required name=search_term_string"}],"publisher":{"@id":"https://rehansaeed.com/#publisher"}},{"@id":"https://rehansaeed.com/seo-friendly-urls-asp-net-core/#webpage","@type":"WebPage","dateModified":"2016-12-17T00:00:00+00:00","datePublished":"2016-12-17T00:00:00+00:00","description":"An SEO friendly URL is human readable and gives your site a higher page rank. Learn how to implement SEO friendly URL's using ASP.NET Core.","name":"SEO Friendly URL's for ASP.NET Core","url":"https://rehansaeed.com/seo-friendly-urls-asp-net-core/","breadcrumb":{"@id":"https://rehansaeed.com/seo-friendly-urls-asp-net-core/#breadcrumb"},"isPartOf":{"@id":"https://rehansaeed.com/#website"},"potentialAction":[{"@type":"ReadAction","target":["https://rehansaeed.com/seo-friendly-urls-asp-net-core/"]}]},{"@id":"https://rehansaeed.com/#identity","@type":"Person","name":"Muhammad Rehan Saeed","url":"https://rehansaeed.com/about/","image":{"@id":"https://rehansaeed.com/#/schema/image/1"},"sameAs":["https://github.com/RehanSaeed","https://www.linkedin.com/in/muhammad-rehan-saeed","https://stackoverflow.com/users/1212017/muhammad-rehan-saeed","https://www.youtube.com/c/MuhammadRehanSaeed","https://www.twitch.tv/rehansaeeduk"]},{"@id":"https://rehansaeed.com/#publisher","@type":"Organization","logo":"https://rehansaeed.com/images/schema/Publisher-600x60.png","name":"Muhammad Rehan Saeed","url":"https://rehansaeed.com"},{"@id":"https://rehansaeed.com/seo-friendly-urls-asp-net-core/#article","@type":"Article","dateModified":"2016-12-17T00:00:00+00:00","datePublished":"2016-12-17T00:00:00+00:00","description":"An SEO friendly URL is human readable and gives your site a higher page rank. Learn how to implement SEO friendly URL's using ASP.NET Core.","headline":"SEO Friendly URL's for ASP.NET Core","inLanguage":"en-GB","url":"https://rehansaeed.com/seo-friendly-urls-asp-net-core/","author":{"@id":"https://rehansaeed.com/#identity"},"image":[{"@type":"ImageObject","url":"https://rehansaeed.com/images/hero/Search-Engine-Optimization-SEO-1366x768.png","caption":"Search Engine-Optimization-SEO","width":"1366","height":"768"}],"isPartOf":{"@id":"https://rehansaeed.com/seo-friendly-urls-asp-net-core/#webpage"},"keywords":[".NET","ASP.NET Core","ASP.NET MVC",".NET Boxed","Friendly URL","Search Engine Optimization (SEO)"],"mainEntityOfPage":{"@id":"https://rehansaeed.com/seo-friendly-urls-asp-net-core/#webpage"},"publisher":{"@id":"https://rehansaeed.com/#publisher"}},{"@id":"https://rehansaeed.com/seo-friendly-urls-asp-net-core/#breadcrumb","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","name":"Blog","item":"https://rehansaeed.com/","position":1},{"@type":"ListItem","name":"SEO Friendly URL's for ASP.NET Core","item":"https://rehansaeed.com/seo-friendly-urls-asp-net-core/","position":2}]},{"@id":"https://rehansaeed.com/#/schema/image/1","@type":"ImageObject","contentUrl":"https://rehansaeed.com/images/author/Muhammad-Rehan-Saeed/Logo-512x512.png","inLanguage":"en-GB","url":"https://rehansaeed.com/images/author/Muhammad-Rehan-Saeed/Logo-512x512.png"}]}
```

## Sitemap

See the full [sitemap](https://rehansaeed.com/sitemap.md) for all pages.
