我有一个更简单的“ ServiceHelper”类,该类在构造函数中带有两个参数:
public ServiceHelper(ILogger<ServiceHelper> log, string serviceName)
((Autofac提供的NLog的ILogger通用包装很好,并且serviceName是Windows服务的名称,用于控制我需要在运行时提供的控件。)
我无法解决如何在运行时如何使用Autofac传递不同的服务名称来创建此类的新实例的问题。这样的事情当然是行不通的,因为我需要在运行时指定不同的服务名称:
builder.RegisterType<ServiceHelper>().As<IServiceHelper>().WithParameter(new NamedParameter("serviceName", null)).InstancePerDependency();
根据我所读的内容,将容器传递过来并手动手动调用Resolve(AutoFac警告的Service Locator“反模式”)是个坏习惯,是吗?如果我做到了,那么我可以做到
container.Resolve<ServiceHelper>(new NamedParameter("serviceName", "some service name"));
但是要想走得更远,我还不确定如何使Autofac将该容器注入类,它只需要注册自己像这样精确?然后让我的类在其构造函数中需要IContainer吗? (这是在使用构造函数注入的C#服务中)
builder.RegisterType<Container>().As<IContainer>().InstancePerDependency();
我也阅读了有关委托工厂的信息,但这似乎并没有使容器必须四处传递。
我的大多数使用ServiceHelper的类,实际上只需要1或2个ServiceHelper来提供特定的服务名称,因此,它不像我要用意想不到的serviceName参数来成千上万,这只是让我的头有点受伤。
您可以通过使用这样的工厂来避免这种情况:
((注:此答案中的所有代码均未经测试,我正在使用不带Visual Studio的计算机上的文本编辑器中编写此代码)
public interface IServiceHelperFactory
{
IServiceHelper CreateServiceHelper(string serviceName);
}
public class ServiceHelperFactory : IServiceHelperFactory
{
private IContainer container;
public ServiceHelperFactory(IContainer container)
{
this.container = container;
}
public IServiceHelper CreateServiceHelper(string serviceName)
{
return container.Resolve<ServiceHelper>(new NamedParameter("serviceName", serviceName));
}
}
[启动时,您像其他所有操作一样在Autofac中注册ServiceHelperFactory
:
builder.RegisterType<ServiceHelperFactory>().As<IServiceHelperFactory>();
然后,当您在其他地方需要ServiceHelper
时,可以通过构造函数注入来获取工厂:
public class SomeClass : ISomeClass { private IServiceHelperFactory factory; public SomeClass(IServiceHelperFactory factory) { this.factory = factory; } public void ThisMethodCreatesTheServiceHelper() { var helper = this.factory.CreateServiceHelper("some service name"); } }
通过使用Autofac通过构造函数注入创建工厂本身,您可以确保工厂了解容器,而不必自己传递容器。我承认,乍看之下,此解决方案与直接将容器传递过来看起来没有什么不同。但优点是您的应用仍与容器分离-唯一已知容器(启动除外)的地方是工厂内部。
编辑:
好的,我忘了。如上所述,我是在没有Visual Studio的计算机上编写此代码的,因此无法测试示例代码。现在,我阅读了您的评论,我记得当我使用Autofac并尝试注册容器本身时,我遇到了类似的问题。我的问题是我需要在构建器中注册容器。但是要获取容器实例进行注册,我需要调用
builder.Build()
...这将创建容器,这意味着之后我无法在构建器中注册内容。我不记得收到的错误消息了,但我想您现在有同样的问题。我发现的解决方案是创建第二个构建器,在此处注册容器,
然后使用第二个构建器更新一个也是唯一的容器
。这是我的一个开源项目中的工作代码:On startup, I register the container::
var builder = new ContainerBuilder(); // register stuff here var container = builder.Build(); // register the container var builder2 = new ContainerBuilder(); builder2.RegisterInstance<IContainer>(container); builder2.Update(container);
...然后用于by aWindowService
to create new WPF windows:
WindowService
我回到了绘图板上,找到了使用Autofac代理工厂实例化对象的“正确”方法。public class WindowService : IWindowService
{
private readonly IContainer container;
public WindowService(IContainer container)
{
this.container = container;
}
public T GetWindow<T>() where T : MetroWindow
{
return (T)this.container.Resolve<T>();
}
}
most依赖性是确定性的,可以预先注册。如何使用Autofac做到这一点是挑战。 @Christian Specht授予的答案是一个很好的答案,但它假定一切都在运行时确定。
要在设计时定义依赖关系链,请参见SO主题http://docs.autofac.org/en/latest/advanced/delegate-factories.html ...