Database-Driven URL Routing in ASP.NET MVC for SEO-Friendly Dynamic URLs

In ASP.NET MVC, URL routing is responsible for mapping an incoming browser request to the right controller and action method.

By default, MVC URLs usually follow a pattern like this:

/Controller/Action/Id

For example:

/Company/Index/5

This works technically, but it is not always the best option for SEO, user experience, or content-driven websites.

A better URL would be:

/satva-solutions

or:

/company/satva-solutions

This type of URL is easier to read, easier to share, and more meaningful for search engines. To create this kind of URL in ASP.NET MVC, we can use database-driven URL routing.

Database-driven URL routing allows us to store SEO-friendly URL slugs in the database and resolve them dynamically at runtime.

When a user visits a URL like /satva-solutions, the application checks the database, finds the matching record, and sends the request to the correct controller action.

In this blog, we will learn how to implement database-driven URL routing in an ASP.NET MVC website using custom routes, URL slugs, and a database lookup.

What Is Database-Driven URL Routing in ASP.NET MVC?

Database-driven URL routing is a technique where URL paths are stored and managed in a database instead of being hardcoded inside route configuration.

For example, instead of accessing a company page using this URL:

/Company/Index/10

we can create a clean, SEO-friendly URL like:

/satva-solutions

Here, satva-solutions is a slug stored in the database. When the request comes in, ASP.NET MVC checks the slug, finds the matching company record, and maps the request to:

CompanyController -> Index Action

This approach is useful for:

  • Company profile pages
  • Product pages
  • Blog pages
  • CMS pages
  • Service pages
  • Landing pages
  • Category pages
  • Location-based pages

Why Use SEO-Friendly Dynamic URLs?

SEO-friendly URLs are important because they make your website easier to understand for both users and search engines.

Compare these two URLs:

/Company/Index/7

and:

/accounting-software-company

The second URL gives more context. A user can understand what the page is about before clicking.

Search engines can also use the URL structure as one of the signals to understand the page topic.

Database-driven SEO-friendly URLs help with:

  • Better readability
  • Better click-through rate from search results
  • Cleaner website structure
  • Easier content management
  • More flexible URL control
  • Better support for CMS-style pages
  • Better handling of dynamic landing pages

For business websites, SaaS websites, directories, marketplaces, and CMS-driven platforms, database-driven routing gives more control over how pages appear in search results.

Default ASP.NET MVC Routing vs Database-Driven Routing

In a standard ASP.NET MVC application, you will usually find a route like this in RouteConfig.cs:

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new 
    { 
        controller = "Home", 
        action = "Index", 
        id = UrlParameter.Optional 
    }
);

This route works well for normal MVC pages, but it depends on controller and action names.

For example:

/Company/Index/5

In database-driven routing, we want to resolve the URL based on a database value:

/satva-solutions

Then internally, the request should be mapped to:

/Company/Index/5

The user sees the clean URL, while MVC still executes the correct controller action.

Example Scenario

Let’s say we have a company directory website.

Each company has a page. Instead of showing company pages like this:

/Company/Index/1

/Company/Index/2

/Company/Index/3

we want URLs like this:

/satva-solutions

/microsoft

/google

/accounting-software-provider

Each slug will be stored in the database. When someone visits /satva-solutions, the application will check the database and find the matching company record.

Step 1: Create a Database Table for SEO-Friendly URLs

First, create a table to store company details and SEO-friendly slugs.

Here is an improved version of the table structure:

CREATE TABLE [dbo].[Companies]
(
    [Id] INT IDENTITY(1,1) NOT NULL,
    [CompanyName] NVARCHAR(250) NOT NULL,
    [SeoFriendlyName] NVARCHAR(250) NOT NULL,
    [MetaTitle] NVARCHAR(250) NULL,
    [MetaDescription] NVARCHAR(500) NULL,
    [Description] NVARCHAR(MAX) NULL,
    [Employees] INT NULL,
    [StartDate] DATETIME NULL,
    [IsActive] BIT NOT NULL DEFAULT 1,

    CONSTRAINT [PK_Companies] PRIMARY KEY CLUSTERED
    (
        [Id] ASC
    )
);

It is also a good idea to add a unique index on the slug column:

CREATE UNIQUE INDEX IX_Companies_SeoFriendlyName
ON [dbo].[Companies] ([SeoFriendlyName]);

This ensures that two companies do not use the same URL slug.

For example, you should not have two records with the same value:

satva-solutions

Duplicate slugs can create routing conflicts and SEO issues.

Step 2: Add Sample Data

Now add a few sample company records:

INSERT INTO [dbo].[Companies]
(
    CompanyName,
    SeoFriendlyName,
    MetaTitle,
    MetaDescription,
    Description,
    Employees,
    StartDate,
    IsActive
)
VALUES
(
    'Satva Solutions',
    'satva-solutions',
    'Satva Solutions - Software Development Company',
    'Learn more about Satva Solutions and its software development services.',
    'Satva Solutions is a software development company specializing in custom web and enterprise solutions.',
    100,
    '2013-01-01',
    1
);

Now, when the user visits:

/satva-solutions

we want ASP.NET MVC to load this company record.

Step 3: Create the Repository Interface

Create an interface named ICompanyRepository.cs.

public interface ICompanyRepository
{
    Company GetCompanyById(int id);

    Company GetCompanyBySeoUrl(string seoFriendlyName);
}

This interface contains two methods:

GetCompanyById fetches the company using the primary key.

GetCompanyBySeoUrl fetches the company using the SEO-friendly slug.

Step 4: Implement the Repository

Now create a repository class.

public class CompanyRepository : ICompanyRepository
{
    private readonly DataDataContext _context;

    public CompanyRepository()
    {
        _context = new DataDataContext();
    }

    public Company GetCompanyById(int id)
    {
        return _context.Companies
            .FirstOrDefault(x => x.Id == id && x.IsActive);
    }

    public Company GetCompanyBySeoUrl(string seoFriendlyName)
    {
        if (string.IsNullOrWhiteSpace(seoFriendlyName))
        {
            return null;
        }

        seoFriendlyName = seoFriendlyName.Trim().ToLower();

        return _context.Companies
            .FirstOrDefault(x => 
                x.SeoFriendlyName.ToLower() == seoFriendlyName 
                && x.IsActive);
    }
}

Important Note

In production, avoid calling ToLower() directly on database columns if your table becomes large.

Instead, store slugs in lowercase format and keep the database collation case-insensitive if suitable for your project.

For example, always save slugs like this:

satva-solutions

accounting-software-company

asp-net-mvc-development

not like this:

Satva Solutions

Accounting Software Company

ASP.NET MVC Development

Step 5: Create the Company Controller

Now create a controller named CompanyController.

public class CompanyController : Controller
{
    private readonly ICompanyRepository _companyRepository;

    public CompanyController()
    {
        _companyRepository = new CompanyRepository();
    }

    public ActionResult Index(int id)
    {
        var company = _companyRepository.GetCompanyById(id);

        if (company == null)
        {
            return HttpNotFound();
        }

        return View(company);
    }
}

This controller action receives the company ID after the URL slug is resolved.

For example:

/satva-solutions

will internally call:

CompanyController -> Index(1)

Step 6: Create the Company View

Create a view at:

Views/Company/Index.cshtml

Example:

@model Company

@{
    ViewBag.Title = Model.MetaTitle ?? Model.CompanyName;
    ViewBag.MetaDescription = Model.MetaDescription;
}

<h1>@Model.CompanyName</h1>

<p>@Model.Description</p>

@if (Model.Employees.HasValue)
{
    <p>Employees: @Model.Employees</p>
}

@if (Model.StartDate.HasValue)
{
    <p>Started On: @Model.StartDate.Value.ToString("dd MMM yyyy")</p>
}

This view displays the company details based on the database record.

You can also use the MetaTitle and MetaDescription fields to dynamically manage SEO metadata.

Step 7: Configure Custom Route in RouteConfig.cs

Open the RouteConfig.cs file.

We need to register a custom route before the default MVC route.

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "SeoFriendlyCompanyRoute",
            url: "{seoFriendlyName}",
            defaults: new 
            { 
                controller = "Company", 
                action = "Index" 
            },
            constraints: new 
            { 
                seoFriendlyName = new SeoFriendlyRouteConstraint() 
            }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new 
            { 
                controller = "Home", 
                action = "Index", 
                id = UrlParameter.Optional 
            }
        );
    }
}

Why Route Order Matters

Route order is very important in ASP.NET MVC.

The MVC routing engine checks routes from top to bottom. If the default route is placed before the custom SEO route, your dynamic slug route may never execute correctly.

So, always place specific custom routes before the default route.

Step 8: Create a Custom Route Constraint

Now create a custom route constraint to check whether the incoming URL exists in the database.

public class SeoFriendlyRouteConstraint : IRouteConstraint
{
    public bool Match(
        HttpContextBase httpContext,
        Route route,
        string parameterName,
        RouteValueDictionary values,
        RouteDirection routeDirection)
    {
        if (!values.ContainsKey(parameterName))
        {
            return false;
        }

        var seoFriendlyName = values[parameterName] as string;

        if (string.IsNullOrWhiteSpace(seoFriendlyName))
        {
            return false;
        }

        var repository = new CompanyRepository();
        var company = repository.GetCompanyBySeoUrl(seoFriendlyName);

        return company != null;
    }
}

This constraint checks whether the URL slug exists in the database.

If the slug exists, the route is matched.

If the slug does not exist, ASP.NET MVC continues checking the next route.

Step 9: Create a Custom Route Class to Pass the Company ID

The route constraint only checks whether the slug exists. But we also need to pass the company ID to the controller action.

For this, we can create a custom route class.

public class SeoFriendlyRoute : Route
{
    public SeoFriendlyRoute(string url, IRouteHandler routeHandler)
        : base(url, routeHandler)
    {
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        RouteData routeData = base.GetRouteData(httpContext);

        if (routeData == null)
        {
            return null;
        }

        var seoFriendlyName = routeData.Values["seoFriendlyName"] as string;

        if (string.IsNullOrWhiteSpace(seoFriendlyName))
        {
            return null;
        }

        var repository = new CompanyRepository();
        var company = repository.GetCompanyBySeoUrl(seoFriendlyName);

        if (company == null)
        {
            return null;
        }

        routeData.Values["controller"] = "Company";
        routeData.Values["action"] = "Index";
        routeData.Values["id"] = company.Id;

        return routeData;
    }
}

This custom route reads the slug from the URL, checks the database, and passes the company ID to the controller.

Step 10: Add an Extension Method for Custom Route Mapping

To make route registration cleaner, create a route extension method.

public static class SeoFriendlyRouteExtensions
{
    public static Route MapSeoFriendlyRoute(
        this RouteCollection routes,
        string name,
        string url,
        object defaults,
        string[] namespaces)
    {
        if (routes == null)
        {
            throw new ArgumentNullException("routes");
        }

        if (url == null)
        {
            throw new ArgumentNullException("url");
        }

        var route = new SeoFriendlyRoute(url, new MvcRouteHandler())
        {
            Defaults = new RouteValueDictionary(defaults),
            DataTokens = new RouteValueDictionary()
        };

        if (namespaces != null && namespaces.Length > 0)
        {
            route.DataTokens["Namespaces"] = namespaces;
        }

        routes.Add(name, route);

        return route;
    }
}

Now update RouteConfig.cs like this:

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapSeoFriendlyRoute(
            name: "SeoFriendlyCompanyRoute",
            url: "{seoFriendlyName}",
            defaults: new 
            { 
                controller = "Company", 
                action = "Index" 
            },
            namespaces: new[] 
            { 
                "YourProject.Controllers" 
            }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new 
            { 
                controller = "Home", 
                action = "Index", 
                id = UrlParameter.Optional 
            }
        );
    }
}

Replace YourProject.Controllers with your actual project namespace.

Step 11: Register Routes in Global.asax

Open Global.asax.cs and make sure routes are registered inside Application_Start.

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    RouteConfig.RegisterRoutes(RouteTable.Routes);
}

Now your custom database-driven routing setup is ready.

Step 12: Test the SEO-Friendly URL

Run the application and visit:

/satva-solutions

The application should:

  • Read satva-solutions from the URL.
  • Check the Companies table.
  • Find the matching company record.
  • Pass the company ID to CompanyController.
  • Load the company details page.

Internally, it works like:

/satva-solutions

maps to:

/Company/Index/1

But the user only sees the SEO-friendly URL.

Handling Invalid URLs

What happens if someone visits a URL that does not exist?

Example:

/random-invalid-company

In this case, the application should return a proper 404 page.

Do not redirect every invalid URL to the home page. That can create SEO confusion and poor user experience.

A better approach is:

if (company == null)
{
    return HttpNotFound();
}

You can also create a custom 404 page for better branding and navigation.

Performance Best Practices for Database-Driven Routing

Database-driven routing is powerful, but if not handled properly, it can create performance issues.

Every request may trigger a database lookup. For high-traffic websites, this can become expensive.

Here are a few best practices.

1. Cache URL Slugs

Instead of checking the database for every request, cache active slugs.

Example:

public Company GetCompanyBySeoUrl(string seoFriendlyName)
{
    string cacheKey = "company_slug_" + seoFriendlyName;

    var cachedCompany = HttpRuntime.Cache[cacheKey] as Company;

    if (cachedCompany != null)
    {
        return cachedCompany;
    }

    var company = _context.Companies
        .FirstOrDefault(x => 
            x.SeoFriendlyName == seoFriendlyName 
            && x.IsActive);

    if (company != null)
    {
        HttpRuntime.Cache.Insert(
            cacheKey,
            company,
            null,
            DateTime.Now.AddMinutes(30),
            Cache.NoSlidingExpiration
        );
    }

    return company;
}

This reduces repeated database calls.

2. Add a Unique Index on Slug

Always index the slug column:

CREATE UNIQUE INDEX IX_Companies_SeoFriendlyName
ON [dbo].[Companies] ([SeoFriendlyName]);

This improves lookup speed and prevents duplicate URLs.

3. Avoid Catching Static Files

Your dynamic route should not interfere with static files like:

/style.css

/logo.png

/script.js

Make sure static files are handled correctly by IIS and ignored from unnecessary route checks.

4. Keep Slugs Simple

Use clean slugs like:

satva-solutions

asp-net-mvc-development

accounting-software-company

Avoid slugs like:

Satva Solutions!!!

company?id=10

asp.net mvc development company

SEO Best Practices for ASP.NET MVC Dynamic URLs

Database-driven routing helps create clean URLs, but URL structure is only one part of SEO.

To get better SEO results, follow these practices.

1. Use Lowercase URLs

Good:

/satva-solutions

Avoid:

/Satva-Solutions

Lowercase URLs are easier to manage and reduce duplicate URL issues.

2. Use Hyphens Between Words

Good:

/asp-net-mvc-development

Avoid:

/asp_net_mvc_development

Hyphens are more readable and commonly used in SEO-friendly URLs.

3. Keep URLs Short and Meaningful

Good:

/custom-software-development

Avoid:

/company/details/custom-software-development-company-profile-page-2025

Shorter URLs are easier to read and share.

4. Add Canonical Tags

If the same content can be accessed from multiple URLs, add a canonical tag.

Example:

<link rel="canonical" href="https://www.example.com/satva-solutions" />

This helps search engines understand the preferred version of the page.

5. Use 301 Redirects When Slugs Change

If you update a slug from:

/satva-solutions-old

to:

/satva-solutions

add a 301 redirect from the old URL to the new one.

This helps preserve SEO value and prevents broken links.

6. Generate a Dynamic XML Sitemap

If your URLs are stored in the database, your sitemap should also be generated from the database.

Example sitemap entries:

<url>
    <loc>https://www.example.com/satva-solutions</loc>
    <lastmod>2026-05-08</lastmod>
</url>

A dynamic sitemap helps search engines discover your database-driven pages.

Common Mistakes to Avoid

1. Placing the Default Route Before the Custom Route

Wrong:

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new 
    { 
        controller = "Home", 
        action = "Index", 
        id = UrlParameter.Optional 
    }
);

routes.MapSeoFriendlyRoute(...);

The custom route may never execute properly.

Place the custom route first.

2. Not Handling Duplicate Slugs

If two records have the same slug, the application may load the wrong page.

Always keep slugs unique.

3. Missing 404 Handling

Do not send all invalid URLs to the home page.

Use:

return HttpNotFound();

or a proper custom 404 page.

4. Querying the Database on Every Request

For high-traffic websites, this can slow down the application.

Use caching for slug lookups.

5. Using Long or Unclear Slugs

Avoid URLs that are too long, unclear, or stuffed with keywords.

Good URLs should be readable and natural.

Database-Driven Routing vs URL Rewriting

Database-driven routing and URL rewriting are sometimes confused, but they are not the same.

PointDatabase-Driven RoutingURL Rewriting
PurposeMaps URL to MVC controller/actionRewrites one URL path to another
Logic LocationASP.NET MVC route systemIIS, middleware, or rewrite rules
Database LookupYes, usuallyNot always
Best ForDynamic pages, CMS pages, SEO slugsRedirects, legacy URL changes
Example/satva-solutions maps to Company/Index/1/old-page rewrites to /new-page

For MVC applications where content is managed from the database, database-driven routing is usually the better choice.

Can We Use This in ASP.NET Core MVC?

The concept is the same, but the implementation is different.

ASP.NET Core MVC uses endpoint routing and middleware-based configuration instead of the classic RouteConfig.cs approach.

If you are working with ASP.NET Core MVC, you would typically configure routing inside Program.cs or use custom route value transformers.

This blog focuses on classic ASP.NET MVC websites.

Conclusion

Database-driven URL routing in ASP.NET MVC is a practical way to create clean, dynamic, and SEO-friendly URLs.

Instead of exposing technical URLs like:

/Company/Index/5

you can create readable URLs like:

/satva-solutions

This improves user experience, supports better SEO structure, and gives your application more flexibility when managing dynamic content.

The key steps are:

  • Store SEO-friendly slugs in the database.
  • Create a repository method to fetch records by slug.
  • Configure a custom MVC route.
  • Resolve incoming URLs dynamically.
  • Handle invalid URLs with 404 pages.
  • Use caching and indexes for better performance.
  • Follow SEO best practices like canonical URLs, lowercase slugs, and 301 redirects.

If you are building an ASP.NET MVC website with dynamic pages, product pages, company profiles, or CMS-driven content, database-driven routing can help you create a cleaner and more search-friendly URL structure.

Need help improving or modernizing your ASP.NET MVC application?

Satva Solutions helps businesses build, maintain, and upgrade ASP.NET MVC, ASP.NET Core, and custom .NET applications.

Whether you need SEO-friendly routing, performance improvement, custom development, or legacy application modernization, our team can help you build a reliable solution.

Talk to our ASP.NET MVC development team today.

Contact us

FAQs

What is database-driven URL routing in ASP.NET MVC?

Database-driven URL routing in ASP.NET MVC is a technique where URL slugs are stored in the database and resolved dynamically when a request comes in. The application checks the slug, finds the matching record, and maps it to the correct controller action.

Why should I use SEO-friendly URLs in ASP.NET MVC?

SEO-friendly URLs are easier for users and search engines to understand. A URL like /satva-solutions is more readable than /Company/Index/5 and gives better context about the page content.

How do I map a database slug to a controller action in MVC?

You can create a custom route or route constraint that reads the incoming slug, checks it against the database, and then assigns the correct controller, action, and ID values to the route data.

Should I cache database-driven routes?

Yes. If your website gets regular traffic, caching slug lookups can improve performance and reduce database load.

What should happen if the slug does not exist?

If the slug does not exist, the application should return a proper 404 page. Avoid redirecting all invalid URLs to the home page.

Can I use database-driven routing for blog pages?

Yes. This approach works well for blog pages, CMS pages, product pages, service pages, category pages, and landing pages.

Is database-driven routing good for SEO?

Yes, when implemented correctly. It helps you create readable, keyword-friendly URLs and gives better control over dynamic page URLs.

Article by

Jeshal kalena

Jeshal Kalena is a passionate Programmer and Tech Lead at Satva Solutions, specializing in RPA, Microsoft.NET Core, ASP.NET, Azure and AWS cloud service integrations. With Master's degree in IT and Computer Applications, Jeshal brings a wealth of knowledge and 13+ years experience to his writing. His blog is a treasure trove of example-driven content, focusing on real-world problems and their solutions in the realm of software programming. Jeshal's philosophy is simple yet powerful: be result-oriented and never give up. Through his insightful posts, he aims to empower fellow programmers with practical tips and techniques to enhance their coding skills and solve complex challenges efficiently.