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

相关问题