3

我正在尝试使用 Autofac 和 Mediatr 实现工作单元。这里的流程如何

建筑学

但我无法让 Autofac 在范围内发送相同的 Unit OfWork 实例(以 DbContext 作为参数)。我想在单个事务中执行整个范围,这意味着当我到达 processHandler 点时,它应该创建一个 DbContext 实例并将同一个实例共享到嵌套处理程序中。这样我就可以在 processhandler 级别创建事务并将相同的事务共享给嵌套处理程序。

这是我的 DI 设置

 builder.Register(ctx =>
        {
            var contextSvc = ctx.Resolve<IContextService>(); // owin context 
            var connBuilder = ctx.Resolve<IDbConnectionBuilder>(); 
            return SapCommandDb.Create(contextSvc.GetMillCode(), connBuilder.BuildConnectionAsync(IntegrationConnectionName, contextSvc.GetMillCode()).Result);
        }).AsSelf().InstancePerLifetimeScope();

        builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IDomainRepository<>)).InstancePerLifetimeScope();
        builder.RegisterType<EFUnitOfWork>().As<IEFUnitOfWork>().InstancePerLifetimeScope();



 public class ProcessHandler : AsyncRequestHandler<IntermediateDocument.Command>
    {
        IMediator _mediator;
        Func<Owned<IEFUnitOfWork>> _uow;
        ILifetimeScope _scope;
        public ProcessHandler(
            ILifetimeScope scope,
            Func<Owned<IEFUnitOfWork>> uow,
            IMediator mediator)
        {
            _mediator = mediator;
            _scope = scope;
            _uow = uow;
        }
        protected async override Task Handle(Command request, CancellationToken cancellationToken)
        {
            foreach (var transaction in request.Transactions)
            {
                using (var scope = _scope.BeginLifetimeScope("custom"))
                {
                    using (var uo = _uow())
                    {
                        await uo.Value.Execute(async () =>
                        {
                            await _mediator.Send(new NestedHandlerGetBySwitch.Command(transaction));
                        });
                    }
                }
            }
        }
    }

上面一个是进程处理程序

public class NestedHandler1 : AsyncRequestHandler<NestedHandler.Command>
        {
            IMediator _mediator;
            IEFUnitOfWork _uow;
            public NestedHandler1(
                IEFUnitOfWork uow,
                IMediator mediator)
            {
                _mediator = mediator;
                _uow = uow;
            }
            protected async override Task Handle(Command request, CancellationToken cancellationToken)
            {
                _uow.Repository.Add(request);
            }
        }

以上是嵌套处理程序的示例。我想要来自 processhandler 的相同 _uow 实例。

EFUNItOFWork 看起来像

public class EfUnitOfWork : IEFUnitOfWork {
    private DbContext _context;
    ABCRepository aBCRepository;
    public ABCRepository ABCRepository { get {
            return aBCRepository = aBCRepository ?? new ABCRepository(_context);
        } }
    public EfUnitOfWork(DbContext context)
    {
        _context = context;
    }

    public Task Add(Entity entity) {
        await _context.AddAsync(entity);
    }
}

我究竟做错了什么 ?

谢谢你。

4

2 回答 2

0

UnitsOfWork、Mediators 和其他东西之间有点混乱。

让我们保持简单并从需求中推断出实现。

  1. 您需要让多个组件共享一个 DbContext。
  2. 单个请求可以由多个处理程序处理多个操作。

鉴于这两个事实,我们可以推断我们需要两个不同的生命周期范围:第一个共享DbContext(我们称之为“UnitOfWork”),第二个对应于每个操作(我们称之为“操作”)。

这个结构的处理将像这样处理:

public class ProcessHandler : AsyncRequestHandler<IntermediateDocument.Command>
{
    // ...ctor 

    protected async override Task Handle(Command request, CancellationToken cancellationToken)
    {
        // inside this using every component asking for an
        // IEFUnitOfWork will get the same instance 
        using (var unitOfWorkScope = _scope.BeginLifetimeScope("UnitOfWork"))
        {
            foreach (var transaction in request.Transactions)
            {
                // we don't need this inner scope to be tagged, AFAICT
                // so probably "Operation" could be omitted.
                using (var scope = unitOfWorkScope.BeginLifetimeScope("Operation"))
                {
                    // I'm not sure what a "mediator" is, I'm just copying the example code
                    var mediator = scope.Resolve<IMediator>();

                    await mediator.Send(...do something with transaction);
                } // here mediator will be disposed, once for each transaction instance
            }
        } // here everything resolved inside unitOfWorkScope will be disposed (and possibly committed).
    }
}

dbContext 必须注册为

builder.RegisterType<EFUnitOfWork>().As<IEFUnitOfWork>().InstancePerMatchingLifetimeScope("UnitOfWork");

很可能您不需要IEFUnitOfWork,但您可以简单地共享 DbContext,在 UnitOfWork 范围内注册它。换句话说,Autofac 的标记范围可以完全取代你的类,AFAICT。

参考 Autofac 文档:
https ://autofac.readthedocs.io/en/latest/lifetime/instance-scope.html#instance-per-matching-lifetime-scope

于 2018-10-09T13:15:10.730 回答
0

IMediator要求 AutoFac 创建 的实例NestedHandler1,因此它将具有与 相同的生命周期范围IMediator

解决它的一种方法是IMediator从“自定义”生命周期范围内解析并使用该生命周期而不是在构造函数中注入它,并确保 UnitOfWork 在此范围内正确注册:

using (var uo = _uow())
{
    using (var scope = _scope.BeginLifetimeScope("custom", x => x.RegisterInstance(uo.Value))
    {
        var mediator = scope.Resolve<IMediator>();

        await uo.Value.Execute(async () =>
        {
            await mediator.Send(new NestedHandlerGetBySwitch.Command(transaction));
        });
    }
}
于 2018-10-05T12:49:37.513 回答