22

如果你不知道我在說什麼,要麼通過the tutorial,並嘗試自己添加依賴注入或嘗試你的運氣與我對問題的解釋。在ASP.NET MVC的ContactsManager教程中有沒有解決依賴注入循環問題的好方法?

注意:此問題不在ASP.NET原始教程的範圍內。本教程只提示使用的模式是依賴注入友好的。

問題是,控制器,ModelStateWrapper和ContactManagerService之間存在依賴關係。

  1. ContactController構造函數接受一個I​​ContactManagerService。
  2. ContactManagerService構造函數接受一個I​​ContactManagerRepository (不重要)和一個IValidationDictionary (ModelStateWrapper實現)
  3. ModelStateWrapper構造函數採用ModelStateDictionary (這是控制器上名爲「ModelState」的屬性)

所以依賴循環是這樣的:控制器>服務> ModelStateWrapper>控制器

如果試圖依賴注入添加到這一點,就會失敗。所以我的問題是;我該怎麼做呢?其他人已經發布了這個問題,但答案很少,不同,而且似乎有點「黑客」。

我目前的解決方案是從IService構造函數刪除IModelStateWrapper,並添加一個初始化方法,而不是像這樣:

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容器嗎?我錯過了什麼嗎?

+0

我不得不承認,我已經做了這個教程3次,不曾經遇到這樣?源代碼中的問題還是手動跟隨教程,如果是後者,您可能會錯過一個步驟? – BinaryMisfit 2009-09-21 06:43:38

+0

這個問題超出了原始教程的範圍,它只暗示了依賴注入,但從來沒有出現過如何顯示它應該如何完成。我會澄清這個問題。 – JohannesH 2009-09-21 06:50:30

回答

11

作爲一般的考慮,循環依賴表明存在設計缺陷 - 我想我可以肯定地說這一點,因爲你是不是代碼:)

的原作者,我不會考慮的初始化方法很好的解決。除非您正在處理加載項方案(您不是),否則方法注入不是正確的解決方案。你幾乎已經知道了,因爲你不滿意你需要手動調用它,因爲你的DI容器不能。

除非我完全錯誤,否則ContactController在其Action方法被調用之前不需要IValidationDictionary實例?

如果這是真的,最簡單的解決方案可能是定義一個IValidationDictionaryFactory接口,並使ContactController構造函數獲取此接口的一個實例。

此接口可以定義是這樣的:

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

需要一個IValidationDictionary實例,然後可以調用Create方法來獲得實例控制器上執行任何操作方法。

默認的實現會是這個樣子:

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

爲什麼匿名downvote? – 2011-05-11 17:09:21

+6

馬克,我不是匿名downvoter,但我相信這裏的問題是如何獲得Controller.ModelState到IContactService實例優雅地填充。在你的解決方案中,如果要將一個IValidationDictionaryFactory實例放入IContactService實例中,我們仍然需要在該服務中使用該控制器的一個實例,以便調用Create方法。 – Ben 2011-12-30 18:55:49

+0

如何在ContactService中獲得IValidationDictionaryFactory?它應該在ContactService中 – 1AmirJalali 2014-05-19 12:12:49

1

每個控制器有一個虛擬方法初始化做這樣的東西。

我覺得有沒有更好的辦法,因爲IValidationDictionary是你當前請求/控制器/ ModelState中和IContactService之間的抽象層。使用構造函數注入將控制器模型注入到服務中,然後將服務注入控制器是根本不可能的。一個必須是第一個。

可能有使用屬性注入的方法嗎?但我認爲這也會很複雜。