2017-01-25 72 views
1

如果我把Lazy放在我的对象的构造函数中,并且X没有在容器中注册,我得到了依赖性解析异常。Autofac可选/懒惰依赖

为什么我会得到这个异常?我不喜欢它,因为我无法在运行时选择组件。示例用例:

class Controller 
{ 
    public Controller(Lazy<A> a, Lazy<B> b) { /* (...) */ } 

Lazy<A> a; 
Lazy<B> b; 

public IActionResult Get(){ 
    if(someConfig) 
    return Json(a.Value.Execute()); 
    else 
    return Json(b.Value.Execute()); 
} 
} 

为此,我需要注册两个组件A和B.即使从未使用B,我的程序也会失败。我希望B是可选的,并且仍由autofac管理。

这是更大的问题,如果我有组件列表,并希望只使用一个。例如:

class Controller 
{ 
    Controller(IEnumerable<Component> components) { /* (...) */ } 

    IActionResult Get() 
    { 
     return components.First(n => n.Name == configuredComponent).Execute(); 

    } 

} 

我不再是异常是没有注册的东西,但仍然是一切都构造。而且使用起来会很尴尬。

回答

7

如果你添加一个引用到Lazy<T>组件,Autofac必须知道(基本上)如何创建将运行应该要解决它内部功能,即使你解决。

基本上,它需要能够在内存中创建这样的:

var lazy = new Lazy<T>(() => scope.Resolve<T>()); 

Autofac要求所有你想要的东西,以解决注册。它不会让你随时注册东西 - 它必须是明确的。所以你要做的事情不会奏效(如你所见)。

取而代之的是,使用该接口的单个​​接口和两个不同的实现。根据您的配置值更改注册。

var builder = new ContainerBuilder(); 
if(someConfig) 
{ 
    builder.RegisterType<A>().As<IService>(); 
} 
else 
{ 
    builder.RegisterType<B>().As<IService>(); 
} 

然后在你的控制器中,注入接口而不是具体的类。

public MyController(Lazy<IService> service) 

也有其他的选择,你可以做,比如使用metadata的组件或keyed services。例如,您可以根据您的配置添加一些元数据并使用该元数据进行解析。

builder.RegisterType<A>() 
     .As<IService>() 
     .WithMetadata("Name", "a"); 
builder.RegisterType<B>() 
     .As<IService>() 
     .WithMetadata("Name", "b"); 

在控制器中,你会得到他们的字典:

public MyController(IEnumerable<Meta<IService>> services) 
{ 
    var service = services.First(s => s.Metadata["Name"].Equals(someConfig); 
} 

这是一个非常简单的例子,但the docs show a lot more

无论如何,界面真的会成为您成功的关键。如果你只是使用具体的课程,他们将不得不注册,不管你是否使用它们。