【问题标题】:Is there a good/proper way of solving the dependency injection loop problem in the ASP.NET MVC ContactsManager tutorial?在 ASP.NET MVC ContactsManager 教程中是否有解决依赖注入循环问题的好方法?
【发布时间】:2009-09-21 06:40:54
【问题描述】:

如果您不知道我在说什么,请通过the tutorial 并尝试自己添加依赖注入,或者试试我对问题的解释。

注意:此问题不在 ASP.NET 原始教程的范围内。本教程仅建议使用的模式对依赖注入友好。

问题基本上是Controller、ModelStateWrapper和ContactManagerService之间存在依赖循环。

  1. ContactController 构造函数采用 IContactManagerService。
  2. ContactManagerService 构造函数采用 IContactManagerRepository (不重要) 和 IValidationDictionary (ModelStateWrapper 实现)
  3. ModelStateWrapper 构造函数采用 ModelStateDictionary(它是控制器上称为“ModelState”的属性)

所以依赖循环是这样的:Controller > Service > ModelStateWrapper > Controller

如果你尝试向它添加依赖注入,它将失败。所以我的问题是;我该怎么办?其他人已经发布了这个问题,但答案很少、不同,而且看起来都有点“hack-ish”。

我目前的解决方案是从 IService 构造函数中删除 IModelStateWrapper 并添加一个 Initialize 方法,如下所示:

public class ContactController : Controller
{
    private readonly IContactService _contactService;

    public ContactController(IContactService contactService)
    {
        _contactService = contactService;
        contactService.Initialize(new ModelStateWrapper(ModelState));
    }

    //Class implementation...
}

public class ContactService : IContactService
{
    private IValidationDictionary _validationDictionary;
    private readonly IContactRepository _contactRepository;

    public ContactService(IContactRepository contactRepository)
    {
        _contactRepository = contactRepository;
    }

    private void Initialize(IValidationDictionary validationDictionary)
    {
        if(validationDictionary == null)
            throw new ArgumentNullException("validationDictionary");

        _validationDictionary = validationDictionary;
    }

    //Class implementation...
}

public class ModelStateWrapper : IValidationDictionary
{
    private readonly ModelStateDictionary _modelState;

    public ModelStateWrapper(ModelStateDictionary modelState)
    {
        _modelState = modelState;
    }

    //Class implementation...
}

有了这个结构,我可以像这样配置我的统一容器:

public static void ConfigureUnityContainer()
{
    IUnityContainer container = new UnityContainer();

    // Registrations
    container.RegisterTypeInHttpRequestLifetime<IContactRepository, EntityContactRepository>();
    container.RegisterTypeInHttpRequestLifetime<IContactService, ContactService>();

    ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container));
}

不幸的是,这意味着服务上的“Initialize”方法必须由控制器构造函数手动调用。有没有更好的办法?也许我以某种方式将 IValidationDictionary 包含在我的统一配置中?我应该切换到另一个 DI 容器吗?我错过了什么吗?

【问题讨论】:

  • 我不得不承认我已经完成了 3 次本教程,但从未遇到过这个?是源代码中的问题还是手动遵循教程,如果是后者,您可能错过了一步?
  • 这个问题超出了原始教程的范围,该教程仅暗示了依赖注入,但从未出现过展示它应该如何完成。我会澄清这个问题。

标签: asp.net-mvc dependency-injection inversion-of-control unity-container


【解决方案1】:

作为一般考虑,循环依赖表明存在设计缺陷 - 我想我可以肯定地说,因为您不是代码的原始作者 :)

我认为 Initialize 方法不是一个好的解决方案。除非您正在处理加载项方案(您不是),否则方法注入不是正确的解决方案。您几乎已经弄清楚了,因为您发现需要手动调用它并不令人满意,因为您的 DI 容器不能。

除非我完全弄错了,否则 ContactController 在调用其 Action 方法之前不需要 IValidationDictionary 实例?

如果这是真的,最简单的解决方案可能是定义一个 IValidationDictionaryFactory 接口并让 ContactController 构造函数获取该接口的一个实例。

这个接口可以这样定义:

public interface IValidationDictionaryFactory
{
    IValidationDictionary Create(Controller controller);
}

控制器上任何需要 IValidationDictionary 实例的 Action 方法都可以调用 Create 方法来获取该实例。

默认实现如下所示:

public class DefaultValidationDictionaryFactory : IValidationDictionaryFactory
{
    public IValidationDictionary Create(Controller controller)
    {
        return controller.ModelState;
    }
}

【讨论】:

  • 马克,我不是匿名投票者,但我相信这里的问题是如何将 Controller.ModelState 优雅地放入 IContactService 实例中以进行填充。使用您的解决方案,如果要将 IValidationDictionaryFactory 实例放入 IContactService 实例中,我们仍然需要来自服务内的控制器实例,以便调用 Create 方法。
  • 如何在 ContactService 中获取 IValidationDictionaryFactory?它应该在 ContactService 中
【解决方案2】:

如何稍微改变/改进设计如下:http://forums.asp.net/t/1486130.aspx

【讨论】:

    【解决方案3】:

    每个控制器都有一个虚拟方法 Initialize 来做类似的事情。

    我认为没有更好的方法,因为 IValidationDictionary 是当前请求/控制器/模型状态和 IContactService 之间的抽象层。将控制器模型状态注入服务,然后将服务注入控制器,使用构造函数注入是根本不可能的。一个人必须是第一。

    可能有使用属性注入的方法吗?但我认为这也会很复杂。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-29
      • 2019-01-29
      • 2017-06-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多