Troubleshooting

Common issues and solutions when using Route Standardization.


Parameter Binding Fails in Minimal APIs

Problem: After enabling route transformation, Minimal API parameters return null or cause binding errors.

Cause: Minimal APIs bind parameters strictly by name. When {userId} is transformed to {user-id}, the binder can’t find the value.

Solution: Use explicit binding with [FromRoute(Name = "...")]:

// Enable transformation
options.Route.MinimalApi.TransformRouteParameters = true;

// Use explicit binding
api.MapGet("/UserAccount/{userId}",
    ([FromRoute(Name = "user-id")] int userId) => Results.Ok(userId));

Or keep parameter transformation disabled (default behavior):

options.Route.MinimalApi.TransformRouteParameters = false; // default

Routes Not Being Transformed

Problem: Routes remain in PascalCase despite configuration.

Possible causes:

  1. Transformation disabled:
// Check these are enabled
options.Route.IsEnabled = true;
options.Route.Controllers.IsEnabled = true; // for MVC
options.Route.RazorPages.IsEnabled = true;  // for Razor Pages
options.Route.MinimalApi.IsEnabled = true;  // for Minimal APIs
  1. Endpoint is excluded:
// Check exclusion lists
options.Route.Controllers.ExcludeControllers // contains your controller?
options.Route.Controllers.ExcludeAreas       // contains your area?
options.Route.MinimalApi.ExcludeTags         // contains your endpoint's tag?
options.Route.MinimalApi.ExcludeRoutePatterns // matches your route?
  1. Hook returning false:
// Check if a hook is skipping your route
options.Route.Hooks.ShouldTransformRoute = (template, model) => {
    Console.WriteLine($"Checking: {template}"); // Debug output
    return true;
};

Query String Parameters Not Binding

Problem: Complex type properties don’t bind from query strings.

Cause: Query parameter names must match the transformed property names.

Solution: Use transformed names in your requests:

public class SearchRequest
{
    public string CategoryName { get; set; }
    public int PageNumber { get; set; }
}

Incorrect request:

/search?CategoryName=Electronics&PageNumber=1

Correct request:

/search?category-name=Electronics&page-number=1

Route Constraints Not Working

Problem: Route constraints like {id:int} cause 404 errors after transformation.

Cause: This typically happens when the constraint syntax is malformed.

Verification: Constraints should survive transformation intact:

{UserId:int}       →  {user-id:int}      ✓
{Slug:regex(...)}  →  {slug:regex(...)}  ✓

Check that your constraint is properly formatted:

// Correct
[HttpGet("{userId:int}")]

// Incorrect (missing colon)
[HttpGet("{userId int}")]

Razor Pages Form Fields Not Binding

Problem: Form submissions fail to bind to [BindProperty] properties.

Cause: Form field names must use transformed names.

Solution: Update your form field names:

<!-- Incorrect -->
<input type="text" name="UserName" />

<!-- Correct -->
<input type="text" name="user-name" />

Or use tag helpers which handle this automatically:

<input asp-for="UserName" />
<!-- Generates: name="user-name" -->

URL Generation Returns Original Names

Problem: Url.Action() or tag helpers generate URLs with PascalCase names.

Cause: AspNetConventions may not be properly registered.

Solution: Ensure proper registration order:

// MVC Controllers
builder.Services.AddControllers()
    .AddAspNetConventions(); // Must be called

// Razor Pages
builder.Services.AddRazorPages()
    .AddAspNetConventions(); // Must be called

var app = builder.Build();

// Minimal APIs
var api = app.UseAspNetConventions(); // Returns RouteGroupBuilder — map endpoints on it

Debugging Transformations

Use the AfterRouteTransform hook to log all transformations:

options.Route.Hooks.AfterRouteTransform = (newRoute, originalRoute, model) =>
{
    Console.WriteLine($"[{model.Identity.Kind}] {originalRoute} → {newRoute}");
};

Output:

[MvcAction] api/UserProfile/GetById/{UserId} → api/user-profile/get-by-id/{user-id}
[MinimalApi] /WeatherForecast/{CityName} → /weather-forecast/{city-name}
[RazorPage] UserProfile/Edit/{UserId} → user-profile/edit/{user-id}

This helps identify which routes are being transformed and which are being skipped.