Skip to main content

Overview

Dev Showcase uses ASP.NET Core’s routing system to map incoming URLs to controller actions. The application has a sophisticated routing configuration that handles profile-specific routes and multilingual URLs.

Route Configuration

All routes are configured in Program.cs using the routing middleware:
Program.cs:12
app.UseRouting();
This enables endpoint routing, which is used to define custom route patterns.

Root Route Redirect

The root URL (/) automatically redirects to the default profile:
Program.cs:16
app.MapGet("/", context =>
{
    context.Response.Redirect("/dataScience", permanent: false);
    return Task.CompletedTask;
});
This ensures that visiting the homepage immediately shows the Data Science profile without requiring users to specify a profile.

Language-Only Routes

When users access a language-specific URL without a profile, they’re redirected to the default profile:
Program.cs:22
app.MapGet("/{lang:regex(^(es|en)$)}", (string lang, HttpContext context) =>
{
    context.Response.Redirect($"/{lang}/dataScience", permanent: false);
    return Task.CompletedTask;
});

Route Constraints

This route uses a regex constraint to ensure the lang parameter only matches valid language codes:
  • {lang:regex(^(es|en)$)} - Only accepts “es” (Spanish) or “en” (English)
  • Invalid values like /fr or /de will not match this route
/es Redirects to /es/dataScience
/en Redirects to /en/dataScience

Profile Routes with Language

The primary routing pattern supports language-specific profile URLs:
Program.cs:28
app.MapControllerRoute(
    name: "profilesWithLang",
    pattern: "{lang}/{profile}",
    defaults: new { controller = "Home", action = "Profile" },
    constraints: new
    {
        lang = "^(es|en)$",
        profile = @"^(dataScience|webDev|dataAnalyst|DataAnalysis)$"
    });

Route Parameters

lang
string
required
Language code - must be “es” or “en”
profile
string
required
Profile identifier - must be one of:
  • dataScience
  • webDev
  • dataAnalyst
  • DataAnalysis

How It Works

1

URL matches pattern

User navigates to /en/dataScience
2

Constraints validated

  • lang = “en” ✓ (matches regex)
  • profile = “dataScience” ✓ (matches regex)
3

Controller action invoked

Routes to HomeController.Profile("dataScience")
4

View rendered

Returns the HomePage view with the specified profile

Examples

/es/dataScience Data Science profile in Spanish
/es/webDev Web Developer profile in Spanish
/es/dataAnalyst Data Analyst profile in Spanish

Profile Routes without Language

For convenience, profiles can be accessed without specifying a language:
Program.cs:38
app.MapControllerRoute(
    name: "profiles",
    pattern: "{profile}",
    defaults: new { controller = "Home", action = "Profile" },
    constraints: new { profile = @"^(dataScience|webDev|dataAnalyst|DataAnalysis)$" });
This allows shorter URLs like:
/dataScience Uses default/cookie language
/webDev Uses default/cookie language
/dataAnalyst Uses default/cookie language
The language displayed depends on the user’s language preference cookie. If no cookie exists, the application defaults to Spanish.

Default MVC Route

A fallback route handles standard MVC convention-based routing:
Program.cs:44
app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=HomePage}/{id?}")
    .WithStaticAssets();

Route Template Breakdown

SegmentDescriptionDefault
{controller=Home}Controller nameHome
{action=HomePage}Action methodHomePage
{id?}Optional parameterNone
This route is rarely used in the application since most navigation goes through the profile routes.

Controller Implementation

The HomeController validates profiles and renders the appropriate view:
Controllers/HomeController.cs:12
private static readonly HashSet<string> ValidProfiles = new(StringComparer.OrdinalIgnoreCase)
{
    "dataScience",
    "webDev",
    "dataAnalyst",
    "DataAnalysis"
};

public IActionResult Profile(string profile)
{
    if (!ValidProfiles.Contains(profile))
        return NotFound();

    ViewData["Profile"] = profile;
    return View("HomePage");
}

Validation Logic

  1. Case-Insensitive Comparison: Uses StringComparer.OrdinalIgnoreCase to handle variations
  2. 404 on Invalid: Returns NotFound() if profile doesn’t exist
  3. ViewData Storage: Passes profile name to the view via ViewData
The same view (HomePage.cshtml) is used for all profiles. JavaScript reads the ViewData["Profile"] value to load the appropriate content from the language JSON files.

Route Precedence

Routes are evaluated in the order they’re defined:
Order matters! More specific routes must be defined before more general ones. If the default route were defined first, it would match before the profile routes could be evaluated.

Adding New Profiles

To add a new profile route:
1

Update ValidProfiles HashSet

Add the profile name to the controller:
private static readonly HashSet<string> ValidProfiles = new(StringComparer.OrdinalIgnoreCase)
{
    "dataScience",
    "webDev",
    "dataAnalyst",
    "DataAnalysis",
    "newProfile"  // Add here
};
2

Update Route Constraints

Add to the regex patterns in both route definitions:
constraints: new
{
    lang = "^(es|en)$",
    profile = @"^(dataScience|webDev|dataAnalyst|DataAnalysis|newProfile)$"
}
3

Add Content to Language Files

Add profile-specific content to en.json and es.json

Testing Routes

You can test routes using curl or a browser:
# With language
curl -I http://localhost:5000/en/dataScience

# Without language
curl -I http://localhost:5000/webDev

# Root redirect
curl -I http://localhost:5000/

Route Debugging

Enable route debugging in development to see which routes match:
Program.cs
if (app.Environment.IsDevelopment())
{
    app.Use(async (context, next) =>
    {
        Console.WriteLine($"Request: {context.Request.Method} {context.Request.Path}");
        await next();
    });
}

Next Steps

Localization

Learn how language switching and multilingual content work

Architecture Overview

Return to the architecture overview

Build docs developers (and LLMs) love