Asp.net-Mvc

在 ASP.NET MVC ContactsManager 教程中是否有解決依賴注入循環問題的好方法?

  • September 21, 2009

如果您不知道我在說什麼,請閱讀本教程並嘗試自己添加依賴項注入,或者通過我對問題的解釋來試試運氣。

**注意:**此問題不在 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));
}

不幸的是,這意味著服務上的“初始化”方法必須由控制器建構子*手動呼叫。*有沒有更好的辦法?也許我以某種方式將 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;
   }
}

引用自:https://stackoverflow.com/questions/1453128