注意:此问题不在ASP.NET原始教程的范围内。本教程仅表明所使用的模式是依赖注入友好的。
问题基本上是在Controller,ModelStateWrapper和ContactManagerService之间有一个依赖循环。
> ContactController构造器需要一个IContactManagerService。
> ContactManagerService构造函数接受一个IContactManagerRepository(不重要)和一个IValidationDictionary(ModelStateWrapper实现的)。
> ModelStateWrapper构造函数接受一个ModelStateDictionary(它是控制器上的一个名为“ModelState”的属性)。
所以依赖循环如下所示:Controller>服务> ModelStateWrapper>控制器
如果您尝试添加依赖注入,它将失败。所以我的问题是我该怎么办?其他人已经发布了这个问题,但答案很少,不同,而且似乎都是“黑客”。
我目前的解决方案是从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)); }
不幸的是,这意味着服务上的“初始化”方法必须由控制器构造函数手动调用。有没有更好的办法?也许我在某种程度上包含我的统一配置中的IValidationDictionary?我应该切换到另一个DI容器吗?我缺少什么?
解决方法
我不会认为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; } }