The PoliNorError.Extensions.DependencyInjection package extends PoliNorError library to provide integration with Microsoft Dependency Injection.
$ dotnet add package PoliNorError.Extensions.DependencyInjectionThe PoliNorError.Extensions.DependencyInjection package extends PoliNorError library to provide integration with Microsoft Dependency Injection.
Get up and running in 3 simple steps:
// Program.cs
services.AddPoliNorError(
Assembly.GetExecutingAssembly());
This scans your assembly for all IPolicyBuilder<> implementations and wires up IPolicy<T> automatically.
public class SomePolicyBuilder : IPolicyBuilder<SomePolicyBuilder>
{
private readonly ILogger<SomePolicyBuilder> _logger;
public SomePolicyBuilder(ILogger<SomePolicyBuilder> logger)
{
_logger = logger;
}
public IPolicyBase Build()
{
return new RetryPolicy(3)
.WithPolicyName("SomeRetryPolicy")
.WithErrorProcessor(new RetryLoggingErrorProcessor(_logger))
.WithWait(new TimeSpan(0, 0, 3))
.AddPolicyResultHandler(pr =>
{
Log.PolicyFailedToHandleException(
_logger,
pr.UnprocessedError,
pr.PolicyName);
});
}
}
Another example:
public class AnotherPolicyBuilder : IPolicyBuilder<AnotherPolicyBuilder>
{
private readonly ILogger<AnotherPolicyBuilder> _logger;
public AnotherPolicyBuilder(ILogger<AnotherPolicyBuilder> logger)
{
_logger = logger;
}
public IPolicyBase Build()
{
return new RetryPolicy(2)
.WithPolicyName("AnotherRetryPolicy")
.WithErrorProcessor(new RetryLoggingErrorProcessor(_logger))
.WithWait(new TimeSpan(0, 0, 1))
.AddPolicyResultHandler(pr =>...);
}
}
, where RetryLoggingErrorProcessor:
public class RetryLoggingErrorProcessor : ErrorProcessor
{
private readonly ILogger _logger;
public RetryLoggingErrorProcessor(ILogger logger)
{
_logger = logger;
}
public override void Execute(Exception error,
ProcessingErrorInfo? catchBlockProcessErrorInfo = null,
CancellationToken token = default)
{
_logger.LogError(error,
"An error occurred while doing work on {Attempt} attempt.",
catchBlockProcessErrorInfo.GetAttemptCount());
}
}
public class Worker
{
private readonly IPolicy<SomePolicyBuilder> _somePolicy;
private readonly IPolicy<AnotherPolicyBuilder> _anotherPolicy;
public Worker(IPolicy<SomePolicyBuilder> somePolicy,
IPolicy<AnotherPolicyBuilder> anotherPolicy)
{
_somePolicy = somePolicy;
_anotherPolicy = anotherPolicy;
}
public async Task DoWorkAsync(CancellationToken token)
{
await _somePolicy.HandleAsync(MightThrowAsync, token);
await _anotherPolicy.HandleAsync(MightThrowAsync, token);
}
private async Task MightThrowAsync(CancellationToken token)
{
await Task.Delay(100, token);
throw new SomeException("Something went wrong.");
}
}
✅ That’s it!
IPolicy<T> and just use it.IPolicyBuilder<TBuilder>
IPolicy<T>
ProxyPolicy<T> which delegates to the builder’s Build() result.Automatic DI Registration
AddPoliNorError() scans assemblies for all IPolicyBuilder<> implementations.IPolicy<T> → ProxyPolicy<T> automatically.IPolicyBuilder<TBuilder>.AddPoliNorError registers the open generic mapping IPolicy<> -> ProxyPolicy<>.IPolicy<TBuilder>, DI resolves ProxyPolicy<TBuilder>.Build() method to produce the actual policy.Handle, HandleAsync, etc.) are delegated to the built policy.For more complex scenarios, PoliNorError.Extensions.DependencyInjection supports an advanced pattern that separates policy creation from policy configuration.
PolicyConfigurator<TPolicy> — an abstract base class for encapsulating cross‑cutting configuration logic (logging, enrichment, etc.).PolicyBuilder<TPolicy, TConfigurator> — an abstract base class that encapsulates policy creation and optional configurator wiring.Create a subclass of PolicyConfigurator<TPolicy> and override the Configure method, where TPolicy is a policy from PoliNorError library.
Inheritors of PolicyConfigurator are automatically resolved from DI.
Create a subclass of PolicyBuilder<TPolicy, TConfigurator> and override the CreatePolicy method, where TPolicy is a policy from PoliNorError library, and TConfigurator inherits from PolicyConfigurator<TPolicy>.
Use custom builders + configurators when:
public class RetryPolicyConfigurator : PolicyConfigurator<RetryPolicy>
{
private readonly ILoggerFactory _loggerFactory;
public RetryPolicyConfigurator(ILoggerFactory loggerFactory)
{
_loggerFactory = loggerFactory;
}
public override void Configure(RetryPolicy policy)
{
var logger = _loggerFactory.CreateLogger(policy.PolicyName);
policy.WithErrorProcessor(new RetryLoggingErrorProcessor(logger))
.AddPolicyResultHandler(pr =>
{
Log.PolicyFailedToHandleException(
logger,
pr.UnprocessedError,
pr.PolicyName);
});
}
}
This configurator:
ILoggerFactory)public class SomePolicyBuilder : PolicyBuilder<RetryPolicy, RetryPolicyConfigurator>, IPolicyBuilder<SomePolicyBuilder>
{
protected override RetryPolicy CreatePolicy() =>
new RetryPolicy(3, retryDelay: ConstantRetryDelay.Create(new TimeSpan(0, 0, 3)))
.WithPolicyName("SomeRetryPolicy");
}
This builder:
RetryPolicy with a fixed delay.RetryPolicyConfigurator.Once created, the configurator (a subclass of PolicyConfigurator) can be shared across multiple builders:
public class AnotherPolicyBuilder : PolicyBuilder<RetryPolicy, RetryPolicyConfigurator>, IPolicyBuilder<AnotherPolicyBuilder>
{
protected override RetryPolicy CreatePolicy() =>
new RetryPolicy(2, retryDelay: ConstantRetryDelay.Create(new TimeSpan(0, 0, 1)))
.WithPolicyName("AnotherRetryPolicy");
}
See samples folder for concrete example.