EntityFrameworkCore.ExecutionStrategy.Extensions
1.0.4
dotnet add package EntityFrameworkCore.ExecutionStrategy.Extensions --version 1.0.4
NuGet\Install-Package EntityFrameworkCore.ExecutionStrategy.Extensions -Version 1.0.4
<PackageReference Include="EntityFrameworkCore.ExecutionStrategy.Extensions" Version="1.0.4" />
<PackageVersion Include="EntityFrameworkCore.ExecutionStrategy.Extensions" Version="1.0.4" />
<PackageReference Include="EntityFrameworkCore.ExecutionStrategy.Extensions" />
paket add EntityFrameworkCore.ExecutionStrategy.Extensions --version 1.0.4
#r "nuget: EntityFrameworkCore.ExecutionStrategy.Extensions, 1.0.4"
#:package EntityFrameworkCore.ExecutionStrategy.Extensions@1.0.4
#addin nuget:?package=EntityFrameworkCore.ExecutionStrategy.Extensions&version=1.0.4
#tool nuget:?package=EntityFrameworkCore.ExecutionStrategy.Extensions&version=1.0.4
📦 ExecutionStrategy.Extensions
Little convenient wrapper for IExecutionStrategy.
Instalation
ExceptionCatcherMiddleware is available on NuGet and can be installed via the below commands:
$ Install-Package EntityFrameworkCore.ExecutionStrategy.Extensions
or via the .NET Core CLI:
$ dotnet add package EntityFrameworkCore.ExecutionStrategy.Extensions
Getting started
Add this to your DbContextOptionsBuilder:
// Here might be any provider you use with retry on failure enabled
builder.UseNpgsql(conn, builder =>
builder.EnableRetryOnFailure());
// Configure ExecutionStrategyExtended
builder.UseExecutionStrategyExtensions<AppDbContext>(
builder => builder.WithClearChangeTrackerOnRetry());
Once you've configured it, you can use it inside your controllers like this:
await context.ExecuteExtendedAsync(async () =>
{
await service.AddUser(user);
});
This is equivalent to the following manual approach:
var strategy = context.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
{
context.ChangeTracker.Clear();
await service.AddUser(user);
});
Why Clear the Change Tracker
The Microsoft documentation recommends recreating a new DbContext on each retry since otherwise it could lead to those bugs:
strategy.ExecuteAsync(
async (context) =>
{
var user = new User(0, "asd");
context.Add(user);
// Transient exception could occure here and IExecutionStrategy will retry execution
// It will lead to adding a second user to change tracker of DbContext
var products = await context.Products.ToListAsync();
await context.SaveChangesAsync();
});
However, manually recreating DbContext in every retry can be inconvenient since you need to recreate instances of services to provide them new DbContext, instead you can clear change tracker on existing DbContext and reuse it.
Transactions
You can manage transactions yourself or by using extension method on action builder:
await context.ExecuteExtendedAsync(async () =>
{
context.Users.Add(new User(0, "asd"));
await context.SaveChangesAsync();
}, builder =>
{
builder.WithTransaction(IsolationLevel.Serializable);
});
Middlewares
If you need to customize the behavior of WithClearChangeTrackerOnRetry, you can do so by providing custom middleware in the builder. In fact, WithTransaction works on top of these middlewares too. Here's how WithClearChangeTrackerOnRetry written internally:
builder.WithMiddleware(async (next, args) =>
{
args.Context.ChangeTracker.Clear();
return await next(args);
});
Default options
Options provided inside DbContextOptionsBuilder are considered as defaults and will be applied for each execution. Besides WithClearChangeTrackerOnRetry, you can provide any middleware to customize behavior within each context.ExecuteExtendedAsync.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net6.0 is compatible. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. 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. |
-
net6.0
- Microsoft.EntityFrameworkCore (>= 6.0.0)
- Microsoft.EntityFrameworkCore.Relational (>= 6.0.0)
-
net7.0
- Microsoft.EntityFrameworkCore (>= 6.0.0)
- Microsoft.EntityFrameworkCore.Relational (>= 6.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.