Tutorials ASP.NET Core Complete Tutorial (ShopNest)

Routing in ASP.NET Core — Conventional and Attribute Routing

Learn Routing in ASP.NET Core — Conventional and Attribute Routing in our free ASP.NET Core Complete Tutorial (ShopNest) series. Step-by-step explanations, examples, and interview tips on Toolliyo Academy.

On this page
Routing in ASP.NET Core — ShopNest Blog
Article 6 of 75 · Module 1: Foundations · ShopNest Blog Website
Target keyword: asp.net core routing · Read time: ~26 min · .NET: 8 / 9 · Project: ShopNest Blog Website

Introduction

Routing is how ASP.NET Core maps an incoming URL like /blog/2025/build-shopnest-with-aspnet-core to the correct controller action. Without routing, every request would hit one endpoint — your blog could never show individual posts, archives, or category pages.

ASP.NET Core supports two complementary styles: conventional routing (central templates in Program.cs) and attribute routing (routes declared on controllers and actions with [Route]). This lesson builds SEO-friendly blog URLs for ShopNest, covers constraints, areas, optional parameters, conflict resolution, and debugging — topics that appear in virtually every MVC interview.

After this article you will

  • Configure conventional route templates with defaults and constraints
  • Apply attribute routing with HTTP verb attributes
  • Use route constraints (int, regex, custom)
  • Set up area routing for admin vs public blog
  • Design SEO-friendly slugs and debug route mismatches

Prerequisites

How routing works — the request pipeline

Level 1 — Analogy

Routing is like a postal sorting office. The envelope (HTTP request) has an address (URL path). The sorter reads the address, looks up rules (route table), and delivers the letter to the right department (controller) and desk (action).

Level 2 — Technical

After middleware runs, UseRouting() selects an endpoint. UseEndpoints() / MapControllerRoute registers MVC routes. The router produces a RouteData dictionary with keys like controller, action, id, plus custom tokens.

// Default conventional route (Program.cs)
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

URL /Posts/Show/42PostsController.Show(42). The ? on {id?} makes the segment optional.

Common misconceptions

❌ MYTH: You must choose conventional OR attribute routing.
✅ TRUTH: Both can coexist; attribute routes often take precedence when matched.

❌ MYTH: Route order never matters.
✅ TRUTH: First matching route wins — register specific routes before catch-all patterns.

Conventional routing — templates, defaults, constraints

Conventional routes are defined once and apply to all controllers following naming conventions.

// ShopNest Blog — SEO-friendly post URLs
app.MapControllerRoute(
    name: "blogPost",
    pattern: "blog/{year:int}/{month:int}/{slug}",
    defaults: new { controller = "Posts", action = "Show" });

app.MapControllerRoute(
    name: "blogArchive",
    pattern: "blog/archive/{year:int}/{month:int?}",
    defaults: new { controller = "Posts", action = "Archive" });

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");
TokenMeaningExample
{slug}Captures any stringbuild-shopnest-with-aspnet-core
{year:int}Constraint — digits only2025
{month:int?}Optional constrained segmentOmit for yearly archive
defaultsValues when segment missingcontroller = "Posts"

Attribute routing

Place routes directly on controllers and actions — ideal for REST-style or versioned APIs and when URLs don't follow one global template.

[Route("blog")]
public class PostsController : Controller
{
    [HttpGet("{year:int}/{month:int}/{slug}")]
    public IActionResult Show(int year, int month, string slug) { ... }

    [HttpGet("archive")]
    [HttpGet("archive/{year:int}")]
    public IActionResult Archive(int? year) { ... }

    [HttpPost("create")]
    public IActionResult Create([FromForm] PostCreateViewModel model) { ... }
}

Combine with HTTP verbs: [HttpGet], [HttpPost], [HttpPut], [HttpDelete]. Same path + different verbs = different actions (like REST).

Route constraints

// Built-in constraints
{id:int}           // 123
{slug:minlength(3)} // at least 3 chars
{slug:regex(^[a-z0-9-]+$)}  // lowercase slug only
{page:range(1,9999)}

// Custom constraint (implements IRouteConstraint)
{slug:slug}  // register in Program.cs:
// options.ConstraintMap.Add("slug", typeof(SlugRouteConstraint));

Constraints reject invalid URLs early — /blog/abc/not-a-year/my-post returns 404 instead of hitting your action with bad data.

Area routing

Areas partition large apps — ShopNest Blog Admin vs public site.

// Areas/Admin/Controllers/PostsController.cs
[Area("Admin")]
[Route("admin/blog/[controller]")]
public class PostsController : Controller
{
    [HttpGet("")]
    public IActionResult Index() => View();
}

// Program.cs
app.MapControllerRoute(
    name: "areas",
    pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");

Admin posts list: /Admin/Posts or /admin/blog/Posts depending on attribute prefix.

Conflicting routes — resolution

  • Specific before general: Register blog/{year}/{slug} before {controller}/{action}.
  • Ambiguous action: Two actions match same template — add constraints or rename routes.
  • Link generation: Use named routes: asp-route="blogPost" in Tag Helpers.
// Debugging: log matched endpoint (Development)
app.Use(async (ctx, next) =>
{
    await next();
    var ep = ctx.GetEndpoint();
    if (ep != null) Console.WriteLine($"Endpoint: {ep.DisplayName}");
});

Install Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation and enable detailed errors in Development to see which route failed.

Hands-on — ShopNest Blog routing

  1. Add Post model with Slug, PublishedAt.
  2. Register blogPost and blogArchive routes in Program.cs.
  3. Implement PostsController.Show loading by year/month/slug.
  4. Generate slugs on create: title.ToLower().Replace(" ", "-") (or Slugify library).
  5. Test: valid URL, wrong year (404), optional archive month.
public IActionResult Show(int year, int month, string slug)
{
    var post = _db.Posts.FirstOrDefault(p =>
        p.Slug == slug && p.PublishedAt.Year == year && p.PublishedAt.Month == month);
    if (post == null) return NotFound();
    return View(post);
}

Common errors & best practices

  • 404 on valid URL: Route registered after default route — reorder in Program.cs.
  • Optional parameter in middle: Not allowed — put optional segments at the end.
  • SEO: Use readable slugs, lowercase, hyphens; include date in path for blogs if desired.
  • Production: Prefer attribute routing for APIs; conventional for traditional MVC sites.

Interview questions

Q1: Conventional vs attribute routing?
A: Conventional uses central templates; attribute routes decorate controllers/actions — attribute gives fine-grained control per endpoint.

Q2: What does {id?} mean?
A: Optional route parameter — URL works with or without that segment.

Q3: How do route constraints help?
A: They validate segment format before model binding — invalid URLs never reach the action.

Q4: What is an Area?
A: Logical folder for controllers/views (e.g. Admin) with separate route prefix.

Q5: Which middleware enables routing?
A: UseRouting() selects endpoint; UseEndpoints/MapControllers executes it.

Summary

  • Routing maps URLs to controller actions via conventional templates or attributes
  • Use constraints and optional parameters for safe, flexible URLs
  • Areas separate Admin from public ShopNest Blog
  • Register specific routes first; debug with endpoint logging

Previous: Controllers and Actions
Next: Views and Razor Syntax

FAQ

Can I use both conventional and attribute routing in one app?

Yes. Many ShopNest-style apps use conventional routes for MVC pages and attribute routes for API controllers in the same project.

Use Tag Helpers: <a asp-route="blogPost" asp-route-year="2025" asp-route-month="5" asp-route-slug="my-post"> or Url.Action with route values.

Questions on this lesson 0

Sign in to ask a question or upvote helpful answers.

No questions yet — be the first to ask!

ASP.NET Core Complete Tutorial (ShopNest)
Course syllabus
Module 1: Foundations
Module 2: Entity Framework Core
Module 3: Dependency Injection & Middleware
Module 4: Authentication & Security
Module 5: Web API
Module 6: Advanced Architecture
Module 7: Testing
Module 8: Deployment & DevOps
Module 9: Real-World Projects
Module 10: Advanced Topics
Toolliyo Assistant
Ask about tutorials, ebooks, training, pricing, mentor services, and support. I use public site content only—not admin or internal tools.

care@toolliyo.com

Need callback? Share your details