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
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="EntityFrameworkCore.ExecutionStrategy.Extensions" Version="1.0.4" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add EntityFrameworkCore.ExecutionStrategy.Extensions --version 1.0.4
#r "nuget: EntityFrameworkCore.ExecutionStrategy.Extensions, 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.
// 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 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. 
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 118 10/12/2023
1.0.3 105 10/12/2023
1.0.2 113 10/12/2023
1.0.1 114 10/11/2023
1.0.0 108 10/11/2023