ASP.NET Core Notes
Attribute Routing AND Conventional Routing
Section titled “Attribute Routing AND Conventional Routing”ASP.NET Core apps can mix the use of conventional routing and attribute routing. It’s typical to use conventional routes for controllers serving HTML pages for browsers, and attribute routing for controllers serving REST APIs.
Actions are either conventionally routed or attribute routed. Placing a route on the controller or the action makes it attribute routed. Actions that define attribute routes cannot be reached through the conventional routes and vice-versa. Any route attribute on the controller makes all actions in the controller attribute routed.
Attribute routing and conventional routing use the same routing engine.
| conventionally-routed controllers | attribute-routed controllers | |
|---|---|---|
| endpoints.MapControllerRoute() | Yes | Yes |
| endpoints.MapAreaControllerRoute() | Yes | Yes |
| endpoints.MapControllers() | Yes |
If you don’t need conventionally-routed controllers, use endpoints.MapControllers() and routing attributes.
Otherwise use endpoints.MapControllerRoute() and/or endpoints.MapAreaControllerRoute()
for both conventionally-routed controllers and attribute-routed controllers.
endpoints.MapControllers() is not needed for attribute routing
if endpoints.MapControllerRoute() or endpoints.MapAreaControllerRoute() is used.
Sources:
- Routing to controller actions in ASP.NET Core
- Conventional vs Attribute Routing In ASP.NET Core Apps
Cookie Names
Section titled “Cookie Names”With ASP.NET Core 5.0 or later, cookie names must conform to the token specification requirements.
These characters cannot be in a cookie name:
( ) < > @ , ; : \ " / [ ] ? = { } space tabSo, for example, you cannot create a cookie with the name company:logging:session-id.
However, underscores and dashes are allowed (company_logging_session-id).
Source: Security: Cookie name encoding removed
Current User
Section titled “Current User”In ASP.NET MVC and Web API, apps often refer to the current user using the ClaimsPrincipal.Current property. This property isn’t set in ASP.NET Core, and any behavior in your app that depends on it will need to migrate from ClaimsPrincipal.Current by using:
ControllerBase.UserHttpContext.User- Request the User as an argument
- Request
IHttpContextAccessorto get currentHttpContext(if it exists)services.AddHttpContextAccessor()to makeIHttpContextAccessoravailable in the DI container- Use
HttpContextAccessor.HttpContext?.Userto get the current user’sClaimPrincipal
Source: Compare authentication and authorization between ASP.NET MVC and ASP.NET Core
Logging Notes
Section titled “Logging Notes”Add this to appsettings.json:
"Logging": { "LogLevel": { "Default": "Trace", "Microsoft.AspNetCore": "Trace", "Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Trace" }},Add this in HostingExtensions.cs:
app.UseHttpLogging();Map vs MapWhen and Path/PathBase
Section titled “Map vs MapWhen and Path/PathBase”Map will update the Request.Path and Request.PathBase to account for branching based on path (trimming the matched path segment off Request.Path and appending it to Request.PathBase), while a seemingly equivalent MapWhen predicate will not. This affects anything downstream that uses the path, such as routing. This is due to the difference between MapMiddleware and MapWhenMiddleware.
Source: Stack Overflow
Middleware Ordering
Section titled “Middleware Ordering”app.UseExceptionHandler();app.UseHsts();app.UseHttpsRedirection();app.UseStaticFiles();app.UseCookiePolicy();app.UseRouting();app.UseCors();app.UseAuthentication();app.UseAuthorization();app.UseSession();app.UseMiddleware<CustomMiddleware>();app.UseEndpoints();Sources: Understanding Middleware In ASP.NET Core, ASP.NET Core Middleware
MVC Method Features
Section titled “MVC Method Features”Source: Dot Net Tutorials
Preprocessor Symbols for Target Frameworks
Section titled “Preprocessor Symbols for Target Frameworks”#if NET8_0_OR_GREATER void NewMethodNotForFullFramework() { }#endifReference: Microsoft Learn - Target Frameworks - Preprocessor Symbols
Sample Middleware to Show All Endpoints
Section titled “Sample Middleware to Show All Endpoints”app.Use(async (context, next) =>{ var currentEndpoint = context.GetEndpoint();
if (currentEndpoint is null) { await next(context); return; }
var currentEndpointRouteRequiredValues = ""; if (currentEndpoint is RouteEndpoint routeEndpoint) { currentEndpointRouteRequiredValues = string.Join(",", routeEndpoint.RoutePattern.RequiredValues.Select(rv => rv.Key + "=" + rv.Value)); }
Console.WriteLine($"Selected Endpoint: {currentEndpoint.DisplayName} ({currentEndpointRouteRequiredValues})");
var endpointDataSource = app.Services.GetService<EndpointDataSource>(); if (endpointDataSource != null) { foreach (var endpoint in endpointDataSource.Endpoints.Cast<RouteEndpoint>()) { Console.WriteLine($"Endpoint: {endpoint.DisplayName} ({string.Join(",", endpoint.RoutePattern.RequiredValues.Select(rv => rv.Key + "=" + rv.Value).ToArray<string>())})"); } }
await next(context);});or after app.UseEndPoints():
var actionDescriptorCollectionProvider = app.Services.GetService<IActionDescriptorCollectionProvider>();var firstRoute = actionDescriptorCollectionProvider.ActionDescriptors.Items[8];var routes = actionDescriptorCollectionProvider.ActionDescriptors.Items .Where(ad => ad.AttributeRouteInfo != null) .Select(ad => ad.AttributeRouteInfo.Template) .ToList();foreach (var route in routes){ Console.WriteLine($"Route Template: {route}");}