CoreDesign.Logging 1.0.4

dotnet add package CoreDesign.Logging --version 1.0.4
                    
NuGet\Install-Package CoreDesign.Logging -Version 1.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CoreDesign.Logging" Version="1.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CoreDesign.Logging" Version="1.0.4" />
                    
Directory.Packages.props
<PackageReference Include="CoreDesign.Logging" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CoreDesign.Logging --version 1.0.4
                    
#r "nuget: CoreDesign.Logging, 1.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CoreDesign.Logging@1.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CoreDesign.Logging&version=1.0.4
                    
Install as a Cake Addin
#tool nuget:?package=CoreDesign.Logging&version=1.0.4
                    
Install as a Cake Tool

CoreDesign.Logging

CoreDesign.Logging provides a DispatchProxy-based logging middleware that wraps any class behind an interface and automatically logs every method invocation, return value, and exception. Classes stay free of log statements while still producing structured, consistent log output for every operation.

Installation

dotnet add package CoreDesign.Logging

Usage

Register a single class with the logging proxy

Replace the standard AddTransient (or AddScoped) call with AddWithLogging:

services.AddWithLogging<IWeatherForecastService, WeatherForecastService>();

The DI container will resolve IWeatherForecastService as a proxy-wrapped instance. The concrete class needs no changes.

Automatic registration with ILoggable

For larger applications, implement the ILoggable marker interface on any class to opt it into automatic logging registration. ILoggable can be applied to services, handlers, or any other class in your application regardless of naming convention.

public class CreateForecastHandler(...) : ICreateForecastHandler, ILoggable { ... }
public class GetForecastHandler(...) : IGetForecastHandler, ILoggable { ... }
public class OrderProcessingService(...) : IOrderProcessingService, ILoggable { ... }

Then register all marked classes in a single call:

services.AddWithLogging(typeof(Program).Assembly);

The overload scans the assembly for every non-abstract class implementing ILoggable, pairs it with each of its non-marker interfaces, and registers a logging proxy for each one. Renaming a class has no effect on whether it gets logging — only the presence of ILoggable matters.

Choosing between the two approaches

Approach When to use
AddWithLogging<TInterface, TImplementation>() Explicit, per-class control. Useful when only a small number of classes need logging, or when you want each registration to be visible at the call site.
AddWithLogging(assembly) Opt-in at the class level via ILoggable. Useful when many classes across an assembly should be logged and you want a single registration call.

What gets logged

Situation Level
Method called Information (method name and serialized parameters)
Method returned a success result Information (method name and serialized return value, truncated to 500 chars by default)
Method returned a NotFoundMessage or BadRequestMessage Warning (same truncation applies)
Method threw an exception Error (exception and method name)

Both synchronous and Task/Task<T> methods are fully supported.

Lifetime

Both overloads default to Transient. Pass a different lifetime when needed:

services.AddWithLogging<IMyService, MyService>(ServiceLifetime.Scoped);
services.AddWithLogging(typeof(Program).Assembly, ServiceLifetime.Scoped);

Sensitive Data

By default, LoggingMiddleware serializes all method parameters and return values into the log output. Two attributes give you control over methods that handle passwords, tokens, or other sensitive information.

[Redact]

Apply [Redact] to any parameter on the interface method that should not appear in logs. The middleware replaces that argument with "[REDACTED]" while still logging all other parameters normally.

public interface IAuthService
{
    Task<LoginResult> LoginAsync(string username, [Redact] string password);
}

The log entry for the example above will include the username value and show "[REDACTED]" in place of password. The actual value is passed to the implementation unchanged.

[Suppress]

Apply [Suppress] to a method on the interface to skip all logging for that method. No invocation, result, or exception entries are written.

public interface ITokenService
{
    [Suppress]
    Task<string> IssueTokenAsync(string userId);
}

Use [Suppress] when the method name or parameter shape itself would be too revealing, or when call volume is high enough that logging every invocation creates more noise than value.

[TruncateLog]

Return values are serialized to JSON and truncated at 500 characters by default. Any result longer than this limit is cut and a note is appended showing the total length:

WeatherForecastService.GetAllAsync returned [{"id":"..."}... [truncated, total 3842 chars]

Apply [TruncateLog] to a method on the interface to override the limit for that method:

public interface IWeatherForecastService
{
    // Raise the limit for a method expected to return larger payloads.
    [TruncateLog(2000)]
    Task<IReadOnlyList<WeatherForecast>> GetAllAsync(CancellationToken ct);

    // Disable truncation entirely for a method that returns a small, critical diagnostic object.
    [TruncateLog(0)]
    Task<ServiceStatus> GetStatusAsync();
}

The default limit of 500 characters is defined by LoggingMiddleware.DefaultMaxResultLength. Parameters are not truncated; use [Redact] to suppress a sensitive parameter entirely.

Further Reading

Design rationale and comparison with Serilog and Serilog.Enrichers.Sensitive: SerilogVsMiddleware.md

Dependencies

  • CoreDesign.Shared for NotFoundMessage and BadRequestMessage result types
  • OneOf for discriminated-union result inspection
  • Microsoft.Extensions.Logging.Abstractions
  • Microsoft.Extensions.DependencyInjection.Abstractions

Feedback

Feedback on this package is welcome. If you run into a missing feature, an unexpected behavior, or something that required more effort than it should have, open an issue at github.com/codyskidmore/CoreDesign/issues or tag @codyskidmore. Suggestions about missing features and priority input are especially appreciated.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.4 54 5/17/2026

1.0.4
- Added ILoggable marker interface. Classes implementing ILoggable are discovered by the new assembly-scanning overload of AddWithLogging.
- Added AddWithLogging(IServiceCollection, Assembly, ServiceLifetime) overload that registers all ILoggable classes in the assembly paired with their interfaces.

1.0.2
- Renamed [SensitiveParameter] attribute to [Redact] and renamed [NoLog] to [Suppress] for clarity and consistency with other CoreDesign libraries.

1.0.1
- Initial release