2016-12-02 40 views
1

有两个项目的解决方案,我遇到了DI问题。 该解决方案由一个类库和一个WebApi2应用程序(它使用类库并公开api)组成。类库中的依赖注入

我在类库中定义了一个Autofac.module,它在项目中设置了所有的DI。

在WebApi2项目中,我创建了DI容器(使用Autofac.WebApi2)并从类库中加载模块。现在,当WepApi2项目中的api控制器请求类库中的服务时,它们会创建所有依赖项,这一切都很好!

问题是,我现在在类库中需要从一个字符串(最终来自数据库)实例化一些类,据我所知,通过使用反射来做到这一点的唯一方法,所以我做像这样:

var ruleType = Type.GetType(rule.RuleImplementation.Implementation); 
var rule = (IRule)Activator.CreateInstance(ruleType,param1,param2); 

的问题是,实现的iRule接口的类也有这需要得到解决的依赖,这是什么让我敲我的我的键盘了,而在现在。

是否有可能以某种方式使用反射和autoFac一起实例化对象?我仍然需要能够将参数传递给对象。

...或者有没有办法以某种方式访问​​容器(它是在webApi2程序集中创建的)并使用它来解决它?我想这应该是某种服务模式,我认为这是一种反模式。

我该如何继续?所有的输入是非常赞赏。

回答

2

使用Activator.CreateInstance创建组件是个坏主意,因为它基本上意味着您正在重新实现容器为您执行的逻辑,但没有DI库为您提供的功能和安全防护。

我在类库中定义了一个Autofac.module,它在项目中设置了所有的DI。

这是你麻烦的根源所在。在应用程序中应该只有一个地方组成对象图(并注册),这是应用程序的Composition Root。虽然组合根(层)和表示层都驻留在同一个项目中很常见,但此组合根可以被看作位于表示层(Web API)之上的独立层。

这样做会消除这个问题,因为在你的组合根目录中你已经有权访问容器。

一个允许使用来自数据库的定义创建规则的好方法是定义一个IRuleActivator抽象。该抽象可以在您的库中定义并在组合根内部实现。这使得实现包装容器,而库保持浑然不觉容器的存在:

// Defined in the library 
public interface IRuleActivator 
{ 
    IRule GetRule(RuleData rule); 
} 

// Defined in the Compostion Root 
public sealed class AutofacRuleActivator : IRuleActivator 
{ 
    private readonly IComponentContext context; 
    public AutofacRuleActivator(IComponentContext context) { 
     this.context = context; 
    } 

    public IRule GetRule(RuleData rule) { 
     Type ruleType = Type.GetType(rule.RuleImplementation.Implementation); 
     return (IRule)this.context.Resolve(ruleType); 
    } 
} 
1

您可以创建工厂的iRule创建:

public IRuleFactory 
{ 
    IRule CreateRule(params); 
} 

对于参数我会用一些去可以注入到实现IRuleFactory中的那种IParamsProviders,RuleImpl只是您实现的对象构造,也可以反映出来:

public class RuleFactory : IRuleFactory 
{ 
    public RuleFactory(IParamsProvider provider) 
    { 
     ... 
    } 

    public IRule CreateRule() 
    { 
     return new RuleImpl(provider.Param1, provider.Param2); 
    } 
} 

将这些接口注册到Ioc中并将它们注入到服务处理程序中。

+0

我喜欢这个解决方案。据我所见,唯一的缺点是我必须将所有规则注入到服务中,而不管是否需要,因为我首先知道在运行时查询数据库。 – iCediCe