Да - проверить Rebus.UnitOfWork - в нем есть нужные вам крючки.
В частности, для Entity Framework вы должны сделать что-то вроде этого:
Configure.With(new CastleWindsorContainerAdapter(container))
.Transport(t => t.UseMsmq("test"))
.Options(o => o.EnableUnitOfWork(
async context => new CustomUnitOfWork(context, connectionString),
commitAction: async (context, uow) => await uow.Commit()
))
.Start();
где CustomUnitOfWork
будет выглядеть примерно так:
class CustomUnitOfWork
{
public const string ItemsKey = "current-db-context";
readonly MyDbContext _dbContext;
public CustomUnitOfWork(IMessageContext messageContext, string connectionString)
{
_dbContext = new MyDbContext(connectionString);
messageContext.TransactionContext.Items[ItemsKey] = this;
}
public async Task Commit()
{
await _dbContext.SaveChangesAsync();
}
public MyDbContext GetDbContext() => _dbContext;
}
и затем вы настроите свой контейнер IoC для разрешения MyDbContext
, извлекая его из текущего контекста сообщения - с помощью Castle Windsor это будет сделано так:
container.Register(
Component.For<CustomUnitOfWork>()
.UsingFactoryMethod(k =>
{
var messageContext = MessageContext.Current
?? throw new InvalidOperationException("Can't inject uow outside of Rebus handler");
return messageContext.TransactionContext.Items
.GetOrThrow<CustomUnitOfWork>(CustomUnitOfWork.ItemsKey);
})
.LifestyleTransient(),
Component.For<MyDbContext>()
.UsingFactoryMethod(k => k.Resolve<CustomUnitOfWork>().GetDbContext())
.LifestyleTransient()
);