ASP.NET Core is a cross-platform, high-performance, open-source framework for building modern, cloud-enabled, internet-connected apps.
When creating API endpoints in ASP.NET Core, you often need to ensure only authenticated users can access certain actions.
The [Authorize]
attribute makes this easy — it automatically blocks unauthenticated requests.
Sometimes, you also load the current user from a database or a user service. In this case, it’s a good practice to add a null check as an extra safety step, even if [Authorize]
is already applied.
Example
[Authorize]
[HttpPost("DoSomething")]
public async Task<IActionResult> DoSomething(RequestModel request)
{
var user = await userService.GetContextUserAsync();
if (user == null)
{
// Safety check in case the user is authenticated but not found in the database
return Unauthorized("User not found.");
}
// Continue with the action
return Ok("Action completed successfully.");
}
Key Ideas
[Authorize]
ensures only authenticated users reach your action.if (user == null)
check.This pattern keeps your API safe, clean, and reliable.
To make your ASP.NET Core services easy to test and maintain, follow this proven pattern. The example below demonstrates how to register a service and configure an HttpClient
with custom handlers, while keeping the design flexible for unit testing.
Register your service interface and implementation as a singleton (or other lifetime as needed). This keeps the service replaceable in tests:
services.AddSingleton<IMyService, MyService>();
Tip: Use TryAdd for safe registration in reusable code
If your registration code is part of a shared library or package, use TryAdd
to avoid overriding existing registrations accidentally:
services.TryAddSingleton<IMyService, MyService>();
Use a named HttpClient to add retry and logging handlers. These handlers improve reliability and diagnostics:
services.AddHttpClient(nameof(MyService))
.AddHttpMessageHandler(s => new RetryHandler(s))
.AddHttpMessageHandler(s => new LoggingHandler(s));
You can call AddMemoryCache()
without worry — it internally prevents duplicates:
services.AddMemoryCache();
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMyClientServices(this IServiceCollection services)
{
ArgumentNullException.ThrowIfNull(services);
services.AddMemoryCache();
services.TryAddSingleton<IMyService, MyService>();
services.AddHttpClient(nameof(MyService))
.AddHttpMessageHandler(s => new RetryHandler(s))
.AddHttpMessageHandler(s => new LoggingHandler(s));
return services;
}
}
Why This Matters
Using this approach ensures your ASP.NET Core apps are easier to maintain, test, and extend.
It’s best practice to tailor logging levels per environment (Development, Staging, Production) by using environment-specific configuration files like appsettings.Development.json
or appsettings.Production.json
.
Example for Development (verbose logging):
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft": "Information",
"System": "Warning",
"YourAppNamespace": "Trace"
}
}
}
Example for Production (concise logging):
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning",
"System": "Warning",
"YourAppNamespace": "Information"
}
}
}
By adjusting log levels per environment, you can capture detailed diagnostics during development while reducing noise and performance impact in production.
ASP.NET Core allows you to customize logging behavior per provider, such as Console or Application Insights. This is useful when you want different verbosity or volume controls depending on the sink.
Example:
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning",
"System": "Warning",
"YourAppNamespace": "Trace"
},
"Console": {
"LogLevel": {
"Default": "Information",
"YourAppNamespace": "Debug"
}
},
"ApplicationInsights": {
"LogLevel": {
"Default": "Error"
}
}
}
}
Information
and Debug
).Use per-provider overrides when you want finer control over logging destinations.
In ASP.NET Core, you can configure logging levels to control the verbosity of logs across your application and third-party frameworks.
A common pattern is to set a default minimum log level (e.g., Warning
) and enable verbose logging (Trace
) only for your own application namespace.
Example configuration in appsettings.json
or an environment-specific file:
{
"Logging": {
"LogLevel": {
"Default": "Warning",
"Microsoft": "Warning",
"System": "Warning",
"YourAppNamespace": "Trace"
}
}
}
"Default": "Warning"
sets a baseline for all logs."Microsoft"
and "System"
are explicitly set to Warning
to reduce noise from framework logs."YourAppNamespace": "Trace"
enables detailed logging for your application code.This ensures your app logs detailed information while keeping system logs concise and manageable.
Logging is a critical aspect of application monitoring and diagnostics. ASP.NET Core provides flexible logging configuration options to help you balance verbosity and noise across different environments and providers.
This series covers best practices for configuring logging levels, including:
Explore the related Snipps below to implement a robust, maintainable logging strategy in your ASP.NET Core applications.
DelegatingHandlers can be tested in isolation:
Mock the Inner Handler:
Inject into DelegatingHandler:
Create HttpClient:
This approach allows for unit testing the DelegatingHandler's logic without making actual HTTP calls.
Multiple DelegatingHandlers can be chained to create a pipeline:
services.AddTransient<LoggingHandler>();
services.AddTransient<AuthenticationHandler>();
services.AddHttpClient("ChainedClient")
.AddHttpMessageHandler<LoggingHandler>()
.AddHttpMessageHandler<AuthenticationHandler>();
In this setup, LoggingHandler
processes the request first, followed by AuthenticationHandler
. The order of registration determines the sequence of execution.
To create a custom DelegatingHandler:
Inherit from DelegatingHandler:
Register the Handler:
In ASP.NET Core, register the handler using IHttpClientFactory
:
Summary:
This video demonstrates how to generate a TreeView structure using data directly from a SQL Server database in an MVC 4 application. The example uses recursive methods to fetch hierarchical data from a parent-child table (such as a category structure). The TreeView is rendered using a combination of Razor and recursive HTML helpers.
Key Steps:
Best For:
Developers working with older ASP.NET MVC versions who need to generate TreeViews from database-driven content, particularly with dynamic data structures.