This post describes how to achieve database transaction, on a command level, with Autofac DI and MediatR.
Sometimes there is a need to share transaction between two different ORMs which uses the same database – in my case Entity Framework and Dapper. It will allow you to be sure that changes, made by two different tools, will be done completely or not. To realize such scenario you can use TransactionScope class. It provides an option to create a transaction, which will be used by SQL connection.
First, you need to create new pipeline behavior – an action which embraces every command. It is a mechanism very well defined in MediatR documentation.
public class TransactionBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
var transactionOptions = new TransactionOptions
IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted,
Timeout = TransactionManager.MaximumTimeout
using (var transaction = new TransactionScope(TransactionScopeOption.Required, transactionOptions,
// handle request handler
var response = await next();
// complete database transaction
The behavior creates transaction every executed action and inside this transaction runs a command handler. These posts (1, 2) describe why, by default, you should create TransactionScope with above options.
Then you need to register your filter during the creation of Autofac ContainerBuilder – typically when the application is being started.
var builder = new ContainerBuilder();
MediatR checks if there are any registered pipeline behaviors and applies them to all incoming commands.
PS. Here you find how to achieve database transaction on a request level.