存储库,UnitOfWork以及服务提供商,他将所有这些依赖项注入我的控制器的正确方法是什么?

时间:2018-04-16 13:55:03

标签: c# asp.net-mvc design-patterns repository unit-of-work

我有一个使用c#在asp.net MVC 5上编写的应用程序。我通过实现以下界面为我的应用程序中的每个模型创建了一个单独的存储库。

public interface IRepository<TModel>
        where TModel : class
{
    TModel Get(int id);
    IEnumerable<TModel> GetAll();
    IQueryable<TModel> Find(Expression<Func<TModel, bool>> predicate);
    TModel SingleOrDefault(Expression<Func<TModel, bool>> predicate);
    TModel Add(TModel entity);
    IEnumerable<TModel> AddRange(IEnumerable<TModel> entities);
    void Remove(TModel entity);
    void RemoveRange(IEnumerable<TModel> entities);
    void Update(TModel entity);
}

虽然,我看到很多实现,每个存储库实现一个Save方法,但事实并非如此。我不认为每个存储库单独保存是一个好习惯。这就是为什么我实施了一个工作单元,以便我的所有存储库都作为一个有凝聚力的单元工作。在我看来,应该是处理保存的工作单元责任,这使得事务能够在需要时回滚或提交更改。

当我实现存储库模式时,我觉得根据需要扩展每个存储库是个好主意,我可以在存储库返回的自定义IQueryable对象中重用查询逻辑和来自我的控制器的简单调用或其他地方,如助手。所以我可以直接在我的存储库中做这样的事情

public IQueryAble<Car> GetCarsByMakerId(int makerId)
{
       // I have typically would have more logic here, but I stripped it out for simplicity.
       Return DbContext.Cars.Where(x => x.MakerId == makerId);
}

然后我意识到在某些情况下,我需要编写一些需要其他存储库来处理业务需求的逻辑。

我开始意识到,使用CRUD操作以外的逻辑扩展每个存储库逻辑可能不是一个好主意。

相反,听起来我应该为我的每个存储库添加一个服务提供程序,其中服务提供程序提供了一个包装业务逻辑/规则的方法。

使用上面的例子,我将创建一个CarServiceProvider,它接受​​一个工作单元的实例。然后,服务提供商将利用注入的工作单元来处理业务需求,这将允许我重用我的业务逻辑并将其从我的存储库中分离出来。因此,将存储库限制为仅CRUD操作以及我称之为Query()的新方法,这使我能够创建查询。

但是,为每个存储库添加服务提供程序的问题意味着我必须向控制器的构造函数中注入更多类。所以我的控制器构造函数需要看起来像这样

public class CarController
{
    public CarController(IUnitOfWork unitOfWork, Ilog log, ICarServiceProvider car, ICarColorService color, ICarMakerService maker, ICarMakerService carMakerService, ICarSellerService seller, IUserServiceProvider user)
    {
        _unitOfWork = unitOfWork;
        _log = log;
        _customer = customer;
        _user = user;
        _car = car;
        _carColor = color;
        _carMaker = maker;
        _seller = seller;
    }

    public ActionResult Index()
    {


    }

    public ActionResult Create()
    {
        var viewModel = new CreateCarViewModel();

        // This will need to set the car colors, car maker, car sizes....
        viewModel.CreateForm(_carColor, _carMaker, _seller);

        return View(viewModel);
    }

    [HttpPost]
    public ActionResult Create(CreateCarViewModel viewModel)
    {
        if(ModelState.IsValid)
        {
            using(var batch = new _unitOfWork.StartBatch())
            {
                try
                {
                    var car = _car.AddNewCar(viewModel, _user.Id);
                    var sellers = car.AddSellers(viewModel.SellerIds);

                    batch.Commit();

                    return RedirectAction("Index");
                } 
                catch (Exception e)
                {
                    batch.rollback();
                    ModelState.AddModelError(string.Empty, e.Message);
                    _log.AddError(e.Message);
                }
            }
        }

        // At this point we know something went wrong, so we need to create the dropdown menus before we can render the view
        // This will need to set the car colors, car maker, car sizes....
        viewModel.CreateForm(_carColor, _carMaker, _seller);

        return View(viewModel);
    }
}

正如您现在所看到的,我将所有这些依赖项填充到我的构造函数中以便能够使用它们,这听起来像我必须处理或解决的新问题。我正在使用IoC容器来解决所有这些依赖关系的好消息。但是我在构造函数中拥有所有这些依赖项这一事实让我很烦恼。

我的问题是

  1. 将所有自定义逻辑从存储库中取出并将其提取到单独的服务提供程序类中是一个好主意吗?
  2. 根据需要一次注入这些服务是可行的方法吗?有没有更好的方法通过为我的所有服务类创建容器来简化这个过程,我会在其中注入一个依赖项而不是3 +?

1 个答案:

答案 0 :(得分:0)