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 feedback@compilenrun.com. I’d greatly appreciate your feedback! :)