ASP.NET Core is a cross-platform, high-performance, open-source framework for building modern, cloud-enabled, internet-connected apps.
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.
Summary:
This tutorial walks through building a TreeView in ASP.NET Core using ViewModel binding and JSON serialization. The TreeView is rendered on the client side using a simple recursive HTML structure. The backend constructs the hierarchy from a static or database source and passes it to the view. The data is structured using parent-child relationships, and the final JSON is passed to the view for rendering. No third-party libraries are used, making it a lightweight and transparent solution.
Key Steps:
Best For:
Developers using ASP.NET Core who want a lightweight, client-side rendered TreeView without relying on jQuery plugins or third-party UI components.