在 ASP.NET MVC ContactsManager 教程中是否有解決依賴注入循環問題的好方法?
如果您不知道我在說什麼,請閱讀本教程並嘗試自己添加依賴項注入,或者通過我對問題的解釋來試試運氣。
**注意:**此問題不在 ASP.NET 原始教程的範圍內。本教程僅建議使用的模式對依賴注入友好。
問題基本上是Controller、ModelStateWrapper和ContactManagerService之間存在依賴循環。
- ContactController 建構子採用 IContactManagerService。
- ContactManagerService 建構子採用 IContactManagerRepository *(不重要)*和 IValidationDictionary (ModelStateWrapper 實現)。
- 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)); }不幸的是,這意味著服務上的“初始化”方法必須由控制器建構子*手動呼叫。*有沒有更好的辦法?也許我以某種方式將 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; } }