.net核心2依赖项注入中是否可以处理循环引用?

时间:2019-07-15 15:37:56

标签: dependency-injection asp.net-core-2.0 circular-dependency

N层设计,我有UserRepository(负责数据库事务),UserManager(负责业务逻辑)和控制器。

我为订单制作OrderManagerOrderRepository

在我的UserManager中,我有一种诸如DoUserStuffThenAddAnOrder()

的方法

此方法会做一些与用户有关的事情,但是会在我的AddOrder()上调用OrderManager

因此我将OrderManager依赖项注入到UserManager中,以便它可以调用与Order相关的方法。

但是然后我在OrderManager遇到了同样的问题,我想DoOrderStuffThenChangeAUser(),因此我将UserManager放入OrderManager

然后我的DI因循环引用而中断;创建OrderManager需要将UserManager注入其中,注入Usermanager则需要Ordermanager等,以至于无限。

有解决方案吗?也许有一种方法可以告诉它将自身作为DI设置中的参数传递?

作为一种解决方法,我分别创建了一个OrderManagerFactory和一个UserManagerFactory,并在每个实例上创建了两个重载的构造函数,例如,创建一个新实例的Controller将DI一个OrderManagerFactory,在构造函数中.GetOrderManager(this)调用重载的构造函数,反之亦然。

但是拥有两个构造函数并不是很好,如果我创建更多的Manager,则可能会创建注入和构造函数的地狱。

是否有一个整洁的解决方案?其他问题表明,如果您遇到此问题,则您的软件架构不正确,但是SRP会要求每位经理自行执行任务并允许他们相互调用以使业务逻辑独立,这似乎是合理的。

这里是一个例子:

public class UserManager {

    private IOrderManager _orderManager;

    public UserManager(IOrderManager orderManager)
    {
        _orderManager = orderManager;
    }

    public void DeleteUser(int userId) {

         if (_orderManager.GetOrdersForUser(userId).Count != 0) {
             throw new Exception("Cannot delete user while orders exist");
         }

         // Do a bunch of stuff connected with deleting a user

         // Send them a goodbye e-mail
         EmailUser(123, "Goodbye");

    }

    public void EmailUser(int userId, string message)
    {
        var userMail = _repository.GetUser(userId).EmailAddress;
        _emailSomething.Send(userMail, message);
    }
}

public class OrderManager {

    private IUserManager _userManager;

    public OrderManager(IUserManager userManager)
    {
        _userManager = userManager;
    }

    public IEnumerable<OrderDto> GetOrdersForUser(int userId)
    {
        return Map(_repo.GetOrdersForUserId(userId));
    }

    public void CancelOrder(int orderId)
    {
        var userId = _repo.GetOrder(orderId).UserId;

        // Cancel order
        var user = _userManager.GetUserById(userId);

        _userManager.EmailUser(userId, "Hello " + user.Name + ", your order has been cancelled");
    }
}

这是不可能的,因为在没有循环引用错误的情况下都无法插入IOrderManager和IUserManager。

1 个答案:

答案 0 :(得分:1)

您的课程听起来好像他们做得太多。解决方案是使用更坚固的方法来重构代码。 DI绝对可以正常工作,但是您遇到问题的事实表明您的方法存在问题,这表明您需要重新考虑-这就是整个模式的目的之一