【发布时间】:2011-12-10 17:50:07
【问题描述】:
我有一个服务,它将在运行时以 XML 形式动态接收配置。我有一个服务类,我需要创建它的几个实例,为每个服务类实例提供不同的依赖项实现。考虑以下示例:
interface ILogger { }
class FileLogger : ILogger { }
class DebugLogger : ILogger { }
class ConsoleLogger : ILogger { }
interface IStorage { }
class RegistrySrorage : IStorage { }
class FileStorage : IStorage { }
class DatabaseStorage : IStorage { }
class MyService
{
ILogger _logger;
IStorage _storage;
public MyService(ILogger logger, IStorage storage)
{
_logger = logger;
_storage = storage;
}
}
我可以像这样手动进行依赖注入:
IEnumerable<MyService> services = new List<MyService>()
{
new MyService(new FileLogger(), new RegistrySrorage()),
new MyService(new FileLogger(), new DatabaseStorage()),
new MyService(new ConsoleLogger(), new FileStorage()),
new MyService(new DebugLogger(), new FileStorage()),
// same implementations as in previous instance are used but with different
// constructor parameter: for example, different destination in FileStorage
new MyService(new DebugLogger(), new FileStorage()),
};
有没有办法创建 XML 配置并拥有一个 DI 框架来提供配置的 MyService 实例的集合,类似于上面的手动示例?
更新
我自己找到了 autofac 的解决方案,但我认为这不是最好的方法。
创建的服务列表:
<component service="System.Collections.IList, mscorlib" type="System.Collections.ArrayList, mscorlib" name="ServicesList">
<parameters>
<parameter name="c">
<list>
<item value="loggerUID,storageUID"/>
</list>
</parameter>
</parameters>
</component>
然后创建解决依赖关系所需的所有组件列表并唯一命名它们:
<component service="Test.ILogger"
type="Test.FileLogger"
name="loggerUID">
<parameters>
<parameter name="logFile" value="C:\Temp\MyLogForSvc_1.log" />
</parameters>
</component>
然后在第一遍的代码中,我检索所有服务的列表(名为“ServicesList”的组件)。在第二遍中,从 XML 加载组件后,我使用提供的组件名称作为键在代码中注册所有服务(这里没有完整性检查):
foreach (string cfg in servicesList)
{
string[] impl = cfg.Split(',');
builder.Register<MyService>(c => new MyService(
c.ResolveKeyed<ILogger>(impl[0]),
c.ResolveKeyed<IStorage>(impl[1])))
.Named<MyService>(cfg);
}
IContainer container = builder.Build();
List<MyService> services = new List<MyService>();
foreach (string svcName in servicesList)
services.Add(container.ResolveNamed<MyService>(svcName));
欢迎提出改进建议。
【问题讨论】:
-
请更新您的问题并仔细解释您的“在运行时从 XML 动态接收配置”的场景。特别是,1)您是指 app.config 还是作为参数传递的任意字符串? 2) 当您需要重新配置与
MyService无关的组件时(他们应该注意到这一点),应该怎么办? 3) 为什么需要 XML 而不是即时编译的 c#? -
1) 任意参数。 2)旧配置的所有实例都被丢弃(GCed)。 3) config 由用户在服务器端组成(不是直接,而是使用某种 UI 来维护 XML 完整性)。
标签: c# .net dependency-injection autofac