2

我一直在尋找另外一個問題:使用Unity來加載網頁API插件提供商

Exception is: InvalidOperationException - The current type, is an interface and cannot be constructed. Are you missing a type mapping?

大家都罵,要求「做錯了」這個問題的人。但是如果你看看描述這個的所有例子和站點,他們都描述了通過構造函數向Controller中注入接口。

這裏的問題是,假設我有一個網頁API,其中,例如在不同的語言返回一個短語:

http://mywebapi/api/SayHello/FR 

的FR告訴我們要在您好法語的WebAPI。我可以輕鬆地使用英文,中文或任何其他語言。

現在,我決定建立一套程序集,每種語言一個,全部實現一個稱爲ILanguage的接口。我創建一個Unity容器,在配置文件中放置命名的類型映射(用「FR」解析ILanguage接口將返回由法國程序集實現的ILanguage等)。

代碼不知道什麼時候調用它將實現的WHICH實現。將一個ILanguage實現注入到Controller構造函數中似乎是錯誤的。只有當URL被解析,我們進入的方法做,我們看到了「FR」參數傳遞的,這告訴我們打電話:

container.Resolve<ILanguage>("FR") 

,以獲得正確的ILanguage接口調用返回相應的短語。

在你的代碼中,教條式的「永遠不會調用container.Resolve」聽起來很好,純粹,但它不能解決這個問題。那麼,推薦的方法是什麼?它看起來很像ServiceLocator,因爲我們想要使用某種「鍵」動態地查找服務,但我當然不希望我的Web API控制器程序集直接瞭解所有這些小語言程序集。我已經在使用上述系統工作了,但我想知道所有DI/IoC純粹主義者會對此代碼發表什麼意見,如果他們不喜歡它,他們如何解決Web中的「動態插件」問題API控制器。

回答

1

我建議讓您的控制器接受語言工廠(即Func<string, ILanguage>),該語言工廠根據您傳入的語言代碼返回ILanguage實現。

的原因,一個工廠函數應在不聲明在構造函數中的任何依賴,而是調用container.Resolve()青睞的是,後者掩蓋了你依賴於ILanguage,而採取在Func<string, ILanguage>的依賴使這個很清楚的事實。

即:

public interface ILanguage 
{ 
    string SayHello(); 
} 

public class Program 
{ 
    public static void Main(string[] args) 
    { 
     UnityContainer container = new UnityContainer(); 
     container.RegisterType<Func<string, ILanguage>>(new InjectionFactory(con => LanguageFactory)); 

     //Use it: 
     MyController controller = container.Resolve<MyController>(); 
     string result = controller.TalkToMe("en"); 
    } 

    private static Func<string, ILanguage> LanguageFactory = delegate(string languageCode) 
    { 
     //Create the correct ILanguage here based on the languageCode. 
     //It's OK to call container.Resolve() here, for example to 
     //resolve named instances. 
     return (ILanguage)null; 
    }; 
} 

public class MyController 
{ 
    private Func<string, ILanguage> _languageFactory; 

    public MyController(Func<string, ILanguage> languageFactory) 
    { 
     _languageFactory = languageFactory; 
    } 

    public string TalkToMe(string languageCode) 
    { 
     ILanguage language = _languageFactory(languageCode); 
     return language.SayHello(); 
    } 
} 

作爲替代方案,你也可以使用您獲得通過到InjectionFactoryIUnityContainer做的語言廠解析:

container.RegisterType<Func<string, ILanguage>>(new InjectionFactory(con => CreateLanguageFactory(con))); 

//... 

private static Func<string, ILanguage> CreateLanguageFactory(IUnityContainer container) 
{ 
    return delegate(string languageCode) 
    { 
     //Create the correct ILanguage here based on the languageCode. 
     ILanguage result = container.Resolve<ILanguage>(languageCode); 
     return result; 
    }; 
} 
+0

我要去花點時間思考這個,我會寫另一條評論。謝謝! – 2014-09-23 18:12:22

相關問題