有没有解决ASP.NET MVC的ContactsManager教程中的dependency injection循环问题的好方法?

如果你不知道我在说什么,或者阅读本教程并尝试自己添加dependency injection,或者试着用我的解释来解决问题。

注意:此问题不在ASP.NET原始教程的范围内。 本教程只提示使用的模式是dependency injection友好的。

问题基本上是Controller,ModelStateWrapper和ContactManagerService之间存在依赖关系。

  1. ContactController构造函数接受一个I​​ContactManagerService。
  2. ContactManagerService构造函数接受一个I​​ContactManagerRepository (不重要)和一个IValidationDictionary (ModelStateWrapper实现)
  3. ModelStateWrapper构造函数接受一个ModelStateDictionary (在控制器上是一个名为“ModelState”的属性)

因此,依赖循环如下所示:Controller> Service> ModelStateWrapper> Controller

如果您尝试向此添加dependency injection,它将失败。 所以我的问题是, 我该怎么办呢? 其他人已经发布了这个问题,但答案很less,不同,都似乎有点“黑客”。

我目前的解决scheme是从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... } 

有了这个构造,我可以像这样configuration我的统一容器:

 public static void ConfigureUnityContainer() { IUnityContainer container = new UnityContainer(); // Registrations container.RegisterTypeInHttpRequestLifetime<IContactRepository, EntityContactRepository>(); container.RegisterTypeInHttpRequestLifetime<IContactService, ContactService>(); ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container)); } 

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

作为一个普遍的考虑,循环依赖表明一个devise缺陷 – 我想我可以放心地说这个,因为你不是代码的原始作者:)

我不会认为Initialize方法是一个好的解决scheme。 除非你正在处理一个插件的情况(你不是),方法注入不是正确的解决scheme。 你几乎已经知道了,因为你发现你不需要手动调用它,因为你的DI容器不能。

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

如果这是真的,最简单的解决scheme可能是定义一个IValidationDictionaryFactory接口,并使ContactController构造函数接受这个接口的一个实例。

这个接口可以这样定义:

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

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

默认的实现看起来像这样:

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

如何稍微改变/改进devise,如下所示: http : //forums.asp.net/t/1486130.aspx

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

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

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