1

我正在尝试使用 DDD 创建一个应用程序,实现Domain Events,使用Entity FrameworkStructureMap进行依赖注入。

我创建了 UnitOfWork 和 Repositories 的抽象。很明显,IUnitOfWork实现封装了DbContext,所有实例都是通过StructureMap(Nested Container的per HTTP request)注入的,所以在所有repositories中注入(也注入)的IUnitOfWork都是同一个实例(顺便说一句,同理,只每个请求创建一个 DbContext 实例)。

UnitOfWork 实现是这样的......

public class EFUnitOfWork : IUnitOfWork, IDisposable
{
    public EFUnitOfWork(ApplicationDbContext dbContext)
    {
        Context = dbContext;
    }

    ...

...和存储库就像..

public class BaseRepository<T, TId> : IRepository<T, TId>, IAggregateRoot
{
    private readonly IUnitOfWork _unitOfWork;

    // All the repositories created are automaticaly injected 
    // with the same IUnitOfWork instance during the request.
    public BaseRepository(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    ...

所有这些都运行良好,我可以使用 IUnitOfWork 实例管理上下文中的更改。

public class UsersService : IUsersService
{

        private readonly IUnitOfWork _unitOfWork;
        private readonly IUserRepository _userRepository;

        public UsersService(IUnitOfWork unitOfWork, IUserRepository userRepository)
        {
            _unitOfWork = unitOfWork;
            _userRepository = userRepository;
        }

        public override CreateUserUseCaseResult HandleExecute(CreateUserUseCaseRequest input)
        {
            var user = Mapper.Map<User>(input.User);
            _userRepository.Insert(user);

            ...

            _unitOfWork.SaveChanges();

            return new CreateUserUseCaseResult
            {
                User = Mapper.Map<UserViewModel>(user)
            };
        }
    }

问题

我想实现领域事件,想法是有一个静态类,该类具有以这种方式发布事件的方法:

    DomainEvents.Publish(new TheDomainEvent() { Data = "something" });

所以我可以在像实体这样的域对象中使用它。

但要让它工作,我不仅需要访问我的容器实例(所有事件处理程序都在其中注册),我需要访问当前嵌套容器实例以共享相同的 IUnitOfWork 实例(我不需要直接 IUnitOfWork,但我需要在所有存储库中注入相同的实例),因此事件处理程序中的任何操作都可以在相同的 DbContext 上执行)。

那么......我怎样才能拥有一个带有发布方法的静态类,以便在域中可用?

目前,我暂时解决了在服务上注入 IDomainBus 实例的问题,因此当前的嵌套容器用于创建事件处理程序实例。

public class SomeService : ISomeService
{
        private readonly IDomainBus _domainBus;

        public UsersService(IDomainBus domainBus, ...)
        {
            _domainBus= domainBus;
        }

        public void PerformSomeOperation(OperationRequest data)
        {
            ...

            _domainBus.Publish(new SomeOperationPerformed() { Data = data });

            ...

但是,如果我想从这样的域实体内部发布事件,则无法使用此解决方案:

public class User : IEntity
{
    public User() { }

    public void UpdatePassword(string newPassword)
    {
        ...

        DomainEvents.Publish(new UserPasswordUpdatedEvent() { User = this });

        ...
    }

一个可能的解决方案...

一种可能的解决方案是将 DbContext 存储在 HttpContext 中并从存储库中检索它。因此,存储库实例和 IUnitOfWork 实例将不同,但使用的 DbContext 将是相同的。

我不喜欢这个解决方案,因为我不想使用 HttpContext。

也许有某种方法可以获取当前请求的嵌套容器......

你能给我一点光吗?谢谢

4

1 回答 1

0

查看 StructureMap 文档,我发现了这种方式。

  • 使用全局根容器创建事件处理程序实例。
  • 添加对 structuremap.web 包的引用。
  • 配置UnitOfWork(实际上是DbContext)注册表,将生命周期设置为HttpContextLifecycle,方式如下:

    var container = new Container(_ =>
    {
        _.For(typeof (IUnitOfWork)).Use(typeof (EFUnitOfWork))
            .SetLifecycleTo(new HttpContextLifecycle());
    

我并不完全相信这个解决方案,但比在 HttpContext 上实现我自己的 UnitOfWork/DbContext 存储要好。

于 2017-05-29T17:34:59.093 回答