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" />
paket add EntityFrameworkCore.ExecutionStrategy.Extensions --version 1.0.4
#r "nuget: EntityFrameworkCore.ExecutionStrategy.Extensions, 1.0.4"
// Install EntityFrameworkCore.ExecutionStrategy.Extensions as a Cake Addin #addin nuget:?package=EntityFrameworkCore.ExecutionStrategy.Extensions&version=1.0.4 // Install EntityFrameworkCore.ExecutionStrategy.Extensions as a Cake Tool #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. |
-
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.