Skip to main content

C# Routing

Routing is a fundamental concept in web development that determines how your application responds to client requests. In C# web development, particularly with ASP.NET Core, routing is the mechanism that maps incoming HTTP requests to specific action methods in your controllers.

Introduction to Routing

When a user navigates to a URL in your web application, the routing system determines which code should execute to generate the response. Think of routing as a traffic control system for your web application - it directs incoming requests to the right destination.

In ASP.NET Core applications, routing is highly configurable and offers various approaches depending on your needs. Whether you're building an MVC application, a Web API, or a Razor Pages app, understanding routing is essential for developing effective C# web applications.

Basic Routing Concepts

URL Patterns

Routing works with URL patterns that typically follow this structure:

https://example.com/{controller}/{action}/{id?}

Where:

  • {controller} is the name of the controller (without the "Controller" suffix)
  • {action} is the name of the action method within that controller
  • {id?} is an optional parameter (the question mark indicates it's optional)

Route Configuration

In ASP.NET Core, you typically configure routes in the Program.cs file (or Startup.cs in older versions). Here's a basic example:

csharp
var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

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

app.Run();

In this example, the default route pattern specifies that:

  • If no controller is specified, use HomeController
  • If no action is specified, use the Index action
  • The id parameter is optional

Route Types in ASP.NET Core

Convention-based Routing

Convention-based routing establishes a convention for URL paths. This is the traditional approach used in ASP.NET MVC.

csharp
app.MapControllerRoute(
name: "blog",
pattern: "blog/{*article}",
defaults: new { controller = "Blog", action = "Article" });

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

In this example, we've added a custom route for blog articles before the default route. The order matters! Routes are evaluated in the order they're registered.

Attribute Routing

Attribute routing allows you to define routes directly on your controller classes or action methods using attributes.

csharp
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
[HttpGet] // GET: /api/products
public IActionResult GetAll()
{
// Return all products
return Ok(new[] { "Product1", "Product2", "Product3" });
}

[HttpGet("{id}")] // GET: /api/products/5
public IActionResult GetById(int id)
{
// Return product with specified ID
return Ok($"Product {id}");
}

[HttpPost] // POST: /api/products
public IActionResult Create([FromBody] ProductModel product)
{
// Create a new product
return CreatedAtAction(nameof(GetById), new { id = 123 }, product);
}
}

Attribute routing is especially common in Web API development and offers more flexibility for complex routing scenarios.

Route Constraints

Route constraints limit what values can match a route parameter. They help ensure that your routes only match the URLs you intend them to match.

csharp
app.MapControllerRoute(
name: "product",
pattern: "product/{id:int}",
defaults: new { controller = "Product", action = "Details" });

In this example, the id parameter must be an integer for the route to match.

Common route constraints include:

ConstraintExampleMatchesDoesn't Match
int{id:int}123abc
bool{active:bool}true, falseyes, no
datetime{date:datetime}2023-10-15october-15
decimal{price:decimal}19.99$19.99
min{id:min(10)}155
alpha{name:alpha}abcabc123
regex{code:regex(^[a-z]{3}[0-9]{3}$)}abc123123abc

Route Parameters and Data Binding

Routes can include parameters that are passed to your action methods.

csharp
[Route("users/{username}")]
public IActionResult UserProfile(string username)
{
// The username parameter comes from the route
return View(new UserProfileViewModel { Username = username });
}

ASP.NET Core can bind route parameters to your action method parameters automatically.

You can also use more complex model binding:

csharp
[HttpGet("search")]
public IActionResult Search([FromQuery] SearchCriteria criteria)
{
// criteria is bound from query string parameters
// e.g., /search?keyword=laptop&maxPrice=1000

var results = _productService.Search(criteria);
return View(results);
}

Practical Example: Building a Blog with Custom Routing

Let's implement a simple blog system with custom routing. We want URLs like:

  • /blog - Blog index
  • /blog/2023/10 - Posts from October 2023
  • /blog/category/tech - Posts in the "tech" category
  • /blog/post/my-awesome-post - Individual post with slug

First, let's create our controller:

csharp
public class BlogController : Controller
{
private readonly IBlogService _blogService;

public BlogController(IBlogService blogService)
{
_blogService = blogService;
}

[Route("blog")]
public IActionResult Index()
{
var posts = _blogService.GetRecentPosts();
return View(posts);
}

[Route("blog/{year:int}/{month:int:range(1,12)}")]
public IActionResult ByMonth(int year, int month)
{
var posts = _blogService.GetPostsByMonth(year, month);
return View("Index", posts);
}

[Route("blog/category/{category}")]
public IActionResult ByCategory(string category)
{
var posts = _blogService.GetPostsByCategory(category);
return View("Index", posts);
}

[Route("blog/post/{slug}")]
public IActionResult Post(string slug)
{
var post = _blogService.GetPostBySlug(slug);
if (post == null)
return NotFound();

return View(post);
}
}

Then, we register these routes in the application:

csharp
app.MapControllers(); // This enables attribute routing

Advanced Routing Features

Route Templates

Route templates can include:

  • Literal segments: /blog
  • Parameter segments: {id}
  • Wildcard segments: {*path}

Route Constraints with Regular Expressions

You can use regular expressions for more complex constraints:

csharp
[Route("products/{sku:regex(^[A-Z]{{3}}\\d{{4}}$)}")]
public IActionResult GetProductBySku(string sku)
{
// Only matches SKUs like "ABC1234"
return Ok($"Product SKU: {sku}");
}

Route Data Values

You can access route data in your action methods or views:

csharp
// In a controller action
var controller = RouteData.Values["controller"];
var action = RouteData.Values["action"];
html
<!-- In a Razor view -->
<p>Current controller: @ViewContext.RouteData.Values["controller"]</p>

URL Generation

You can generate URLs using the Url helper in controllers or views:

csharp
// In a controller
var url = Url.Action("Details", "Product", new { id = 123 });
html
<!-- In a Razor view -->
<a asp-controller="Product" asp-action="Details" asp-route-id="123">View Product</a>

Common Routing Scenarios and Solutions

Localizing URLs

csharp
app.MapControllerRoute(
name: "localized",
pattern: "{culture}/{controller=Home}/{action=Index}/{id?}",
constraints: new { culture = new RegexRouteConstraint("^[a-z]{2}(-[a-z]{2})?$") });

This allows URLs like /en-us/products/details/5.

Versioned APIs

csharp
[Route("api/v{version:apiVersion}/[controller]")]
[ApiVersion("1.0")]
[ApiVersion("2.0")]
public class ProductsController : ControllerBase
{
[HttpGet]
[MapToApiVersion("1.0")]
public IActionResult GetV1()
{
return Ok("Version 1.0");
}

[HttpGet]
[MapToApiVersion("2.0")]
public IActionResult GetV2()
{
return Ok("Version 2.0");
}
}

This allows you to have different implementations for different API versions.

Best Practices for Routing

  1. Keep URLs Simple and RESTful

    • Use nouns for resources
    • Use HTTP verbs to indicate actions (GET, POST, PUT, DELETE)
    • Keep URLs clean and human-readable
  2. Order Your Routes Correctly

    • More specific routes should come before more general routes
  3. Use Attribute Routing for APIs

    • Attribute routing is generally clearer for API endpoints
  4. Avoid Route Parameter Naming Conflicts

    • Don't use the same parameter name in different parts of the route
  5. Use Meaningful Route Names

    • When naming routes, choose descriptive names that reflect their purpose
  6. Prefer Routing Over Query Strings for Major Resource Identifiers

    • Use /products/categories/5 rather than /products?categoryId=5

Summary

Routing is a crucial component of C# web development with ASP.NET Core. It determines how URLs map to your application's code and greatly affects the user experience of your web application.

In this guide, we've covered:

  • Basic routing concepts and configuration
  • Convention-based and attribute routing
  • Route constraints and parameters
  • Practical examples of implementing custom routes
  • Advanced features and best practices

Understanding routing thoroughly will help you build more organized, maintainable, and user-friendly web applications.

Additional Resources and Exercises

Resources

Exercises

  1. Basic Routing Configuration

    • Create a new ASP.NET Core MVC application
    • Configure a custom route for a "Blog" controller that supports year and month parameters
  2. Route Constraints Practice

    • Implement a product catalog with routes that enforce proper constraints on IDs and categories
  3. RESTful API Routing

    • Create a RESTful API for a resource of your choice (e.g., books, movies, recipes)
    • Implement GET, POST, PUT, and DELETE endpoints with appropriate attribute routing
  4. Advanced URL Generation

    • Create a navigation system that dynamically generates URLs based on the current culture and user permissions
  5. Slugified URLs

    • Implement a news article system with SEO-friendly slugified URLs (e.g., /news/my-awesome-article) instead of ID-based URLs

By practicing these exercises, you'll gain hands-on experience with C# routing and be better prepared to implement effective routing in your real-world applications.



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)