如何在 ScopedLifestyle.Flowing 的上下文中在 decoratee 和 decorator 之间共享实例

How to share instance between decoratee and decorator in the context of ScopedLifestyle.Flowing

我不明白如何使用 DI 容器在 decoratee 和 decorator 之间共享实例。

下面的例子说明了我的问题。 context 实例在 TransactionCommandDecoratorCommand 服务之间共享。

var context = UowFactory.GetUnitOfWork();

var command = new TransactionCommandDecorator(
    context,
    new Command(context));
    
command.Execute(new CommandParams { });

context.dispose();

基本上我需要有很多与数据库交互并调用存储库的命令。然后我想通过使用包装命令服务的装饰器来应用事务。

问题是我不知道如何在装饰者和被装饰者之间共享上下文(如示例中所示),因为我需要为每次执行命令创建一个新的 DbContext 实例.

你能解释一下我如何在范围流动的上下文中使用简单注入器使它工作吗(ScopedLifestyle.Flowing)。

装饰器和装饰器的一个可能实现示例

命令示例:

public Command(IUnitOfWork uow) => _uow = uow;

public DbResult Execute(CommandParams args)
{
    _uow.Repo1.Add(args.Item);
    _uow.Repo1.Add(args.Item2);
    _uow.Repo1.Remove(args.Item3);
}

事务命令装饰器:

public class TransactionCommandDecorator : ICommand
{
    public TransactionCommandDecorator(IUnitOfWork uow, ICommand command)
    {
        _uow = uow;
        _command = command;
    }

    public DbResult Execute(commandParams args)
    {
        try
        {
            var transaction = _uow.GetContext().Database.GetTransaction();
            var ret = _command.Execute(args);
            
            if (!ret.Success)
            {
                transaction.Discard();
                return;
            }
            
            transaction.Commit();
        }
        catch
        {
            transaction.Discard();
        }
        finally
        {
            transaction.Dispose();
        }
    }
}

可以在同一个Scope中的类之间共享IUnitOfWork,方法是将其注册为Lifestyle.Scoped,如下例所示:

container.Register<IUnitOfWork>(() => UowFactory.GetUnitOfWork(), Lifestyle.Scoped);
container.Register<ICommand, Command>();
container.RegisterDecorator<ICommand, TransactionCommandDecorator>();

用法(使用ScopedLifestyle.Flowing):

using (var scope = new Scope(container))
{
    ICommand command = scope.GetInstance<ICommand>();

    command.Execute(new CommandParams { });
}

用法(使用环境作用域):

using (AsyncScopedLifestyle.BeginScope(container))
{
    ICommand command = container.GetInstance<ICommand>();

    command.Execute(new CommandParams { });
}