3

我正在设置一个 asp.Net Mvc 4 应用程序并希望使用洋葱架构模式对其进行配置。过去我使用过这样的工作单元模式

public class UnitOfWork : IUnitOfWork, IDisposable
{

private IRepository<CallModel> _callRepo;
private IRepository<UserModel> _userRepo;

    public IRepository<CallModel> CallRepo
    {
        get
        {
            if (_callRepo == null)
            {
                _callRepo = new Repository<CallModel>();
            }
            return _callRepo;
        }
    }

    public IRepository<UserModel> UserRepo
    {
        get
        {
            if (_userRepo == null)
            {
                _userRepo = new Repository<UserModel>();
            }
            return _userRepo;
        }
    }
}

然后,我会将 UnitOfWork 类的实例传递给 Controller 以执行类似这样的简单 CRUD 操作。

    public class QuestionsController : Controller
{
    private IUnitOfWork _unitOfWork;

    [Inject]
    public QuestionsController(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
    }

我已将应用程序分成三个项目。

  1. 基础设施
  2. 网络

我在 Core 项目中有我的所有接口,在 Infrastructure 项目中有 IRepository 接口的实现。如果我将 UnitOfWork 类放在核心项目中,那么因为它在基础设施项目中需要一个新的存储库,所以我正在创建从核心到基础设施的依赖关系。如果我将它包含在基础架构中,那么 Web 项目(具有控制器)将依赖于基础架构,整个解决方案最终看起来不像洋葱,而更像意大利面条。

4

4 回答 4

1

我在 Core 项目中有我的所有接口,在 Infrastructure 项目中有 IRepository 接口的实现。如果我将 UnitOfWork 类放在核心项目中,那么因为它在基础设施项目中需要一个新的存储库,所以我正在创建从核心到基础设施的依赖关系。

嗯,真的不是。您的工作单元类应该依赖于 IRepository,而不是 Repository 实现本身。如果您使用的是依赖注入,这应该不会造成问题,因为它应该找到正确的类型并在运行时提供它。我不确定在不使用 DI 的情况下是否可以使用 Onion 架构。

另请参阅 david.s 的回答,因为这正是我设置的方式 - 有一个项目仅用于连接依赖项。

于 2013-02-13T16:54:40.703 回答
0

我希望 david.s 创建名为 DependencyResolution 的项目,但让它引用 Web、Core 和 Infrastructure。

在那个项目中,你可以这样做:

[assembly: PreApplicationStartMethod(typeof(Start), "Register")]

namespace DependencyResolution
{
    public static class Start
    {
        public static void Register()
        {
            UnityConfig.Register();
        }
    }
}

并注册 DI。

namespace DependencyResolution
{    
    public static class UnityConfig
    {
        public static void Register()
        {
            DependencyResolver.SetResolver(new UnityDependencyResolver());
        }
    }
}

因此,无需在 Web 和基础架构之间进行引用。

此致

于 2013-02-26T13:20:17.523 回答
0

值得一提的是,我实现了自己的库,它应用 UnitOfWork 模式与我之前在任何代码示例中看到的略有不同,但我发现它在实践中运行良好。简而言之:我通过创建一个范围然后在必要时在环境 unitofwork(-manager) 中征用资源来复制 .NET Transactions 的工作方式。基本上发生的是,当处理新消息/请求时,会执行以下代码:

public void Handle<TMessage>(TMessage message)
{
    using (var scope = CreateMessageProcessorContextScope())
    {
        HandleMessage(message);
        scope.Complete();
    }
}

现在就像事务一样,只要线程仍在范围内,就会出现一个环境 UnitOfWork 控制器,其中在请求期间使用和更改的所有资源都可以动态登记。他们通过实现具有两种方法的 IUnitOfWork 接口来做到这一点:

public interface IUnitOfWork
{
    bool RequiresFlush();

    void Flush();
}

然后,实现此接口的实例可以按如下方式登记自己:

MessageProcessorContext.Current.Enlist(this);

通常,存储库类将实现此接口,并且当它检测到它的托管聚合被更改/添加/删除时,它可以自己登记(忽略双重登记)。

在我的例子中,该框架假定您正在使用一个 IOC 框架,它将为您解析所有消息处理程序和存储库,因此我通过让它注入当前 IUnitOfWorkManager 的实例来更容易地加入环境工作单元控制器需要的构造函数。这样,工作单元管理器的依赖关系和需要刷新的实际部分(存储库、服务等)被反转:

internal sealed class OrderRepository : IOrderRepository, IUnitOfWork
{
    private readonly IUnitOfWorkManager _manager;
    private readonly Dictionary<Guid, Order> _orders;

    public OrderRepository(IUnitOfWorkManager manager)
    {
        if (manager == null)
        {
            throw new ArgumentNullException("manager");
        }
        _manager = manager;
    }

    bool IUnitOfWork.RequiresFlush()
    {
        return _orders.Values.Any(order => order.HasChanges());
    }

    void IUnitOfWork.Flush()
    {
        // Flush here...
    }

    public void Add(Order order)
    {
        _orders.Add(order.Id, order);
        _manager.Enlist(this);
    }
}

一旦成功处理了请求(没有抛出异常),将调用 scope.Complete() 触发控制器检查所有登记的项目是否(仍然)需要刷新(通过调用 RequiresFlush()),如果是,则刷新它们(通过调用 Flush())。

总而言之,这允许一个非常可维护的解决方案(在我看来),可以在不更改任何主 unitofwork 类的情况下即时添加新的存储库和其他依赖项,就像 TransactionManager 不需要预先知道哪些项目可能参与任何给定的交易。

于 2013-06-13T12:24:28.807 回答
0

我所做的是有另一个名为的项目,它具有对我的 IoC 容器的DependencyResolution引用Core和配置的位置。Infrastructure然后我只能DependencyResolutionWeb项目中引用。

于 2013-02-13T16:50:14.993 回答