我发现了两个与我的问题相近的相关帖子,但仍然没有回答我正在寻找的内容。
Which design patterns can be applied to the configuration settings problem?
Should my program's "services" be responsible to get their own configuration?
我有一个使用AutoFac作为DI容器的应用程序并遇到了以下问题。我有在启动时向AutoFac注册的类,但是一些构造函数参数只在运行时才知道。我制作了一个样本来展示我的内涵。注释显示代码中我想要检索类实例的位置,并在此时注入一些配置数据。
它背后的想法是将通用设置提供程序的实现与某些类的配置分开。应从设置提供程序(ISettingsProvider)检索配置,转换为类相关的设置类(FooSettings),然后在创建时将其注入该类(Foo)。
有关如何执行此操作的任何建议吗?
我的样本:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Autofac;
namespace FooNamespace
{
internal static class Program
{
private static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<SettingsProvider>().As<ISettingsProvider>().SingleInstance();
builder.RegisterType<AnotherService>().As<IAnotherService>().SingleInstance();
builder.RegisterType<Foo>();
builder.RegisterType<ClientClass>();
var container = builder.Build();
var myClient = container.Resolve<ClientClass>();
myClient.DoSomething();
}
}
public class Foo
{
private FooSettings _settings;
private IAnotherService _anotherService;
public Foo(IAnotherService anotherService, FooSettings settings)
{
_anotherService = anotherService;
_settings = settings;
}
}
public class FooSettings
{
public string SettingA { get; private set; }
public string SettingB { get; private set; }
public FooSettings(string settingA, string settingB)
{
SettingA = settingA;
SettingB = settingB;
}
}
public class ClientClass
{
private readonly ISettingsProvider _settingsProvider;
public ClientClass(ISettingsProvider settingsProvider)
{
_settingsProvider = settingsProvider;
}
public void DoSomething()
{
var providerSettings = _settingsProvider.GetSettings("fooSettings");
var fooSettings = new FooSettings(providerSettings[0], providerSettings[1]);
// what is the best way to get an instance of foo with the fooSettings set at runtime
// when Foo and IAnotherService have been registered with AutoFac
}
}
public interface ISettingsProvider
{
string[] GetSettings(string settingsGroup);
}
class SettingsProvider : ISettingsProvider
{
public string[] GetSettings(string settingsGroup)
{
return new string[2] {"valueA", "valueB"};
}
}
public interface IAnotherService
{
}
class AnotherService : IAnotherService
{
}
}
答案 0 :(得分:3)
当我需要将运行时值作为依赖项注入时,我总是使用Abstract Factory pattern 。
定义工厂界面
public interface IFooFactory
{
Foo CreateFoo();
}
借助autofac提供的Delegate Factories支持实现界面。如果您依赖于任何委托,autofac将为您创建具有除委托所接受的依赖项之外的所有依赖项的实现。
public class FooFactory : IFooFactory
{
private readonly Func<FooSettings, Foo> creationFunc;
private readonly ISettingsProvider settingsProvider;
public FooFactory(Func<FooSettings, Foo> creationFunc, ISettingsProvider settingsProvider)
{
if (creationFunc == null) throw new ArgumentNullException("creationFunc");
if (settingsProvider == null) throw new ArgumentNullException("settingsProvider");
this.creationFunc = creationFunc;
this.settingsProvider = settingsProvider;
}
public Foo CreateFoo()
{
var providerSettings = settingsProvider.GetSettings("fooSettings");
var fooSettings = new FooSettings(providerSettings[0], providerSettings[1]);
return creationFunc(fooSettings);
}
}
依赖IFooFactory
代替ISettingsProvider
public class ClientClass
{
private readonly IFooFactory fooFactory;
public ClientClass(IFooFactory fooFactory)
{
this.fooFactory = fooFactory;
}
public void DoSomething()
{
var foo = fooFactory.CreateFoo();
//Do whatever with foo
//Your foo is now injected with another service and settings too:)
}
}
当然注册工厂
builder.RegisterType<FooFactory>().As<IFooFactory>();
答案 1 :(得分:0)
您可以FooSettingsProvider
取决于SettingsProvider
并将lambda注册为FooSettings
。
例如:
public interface ISettingsProvider<TSettings> where TSettings : ISettings
{
TSettings Settings { get; }
}
public class FooSettingsProvider : ISettingsProvider<FooSettings>
{
public FooSettingsProvider(SettingsProvider settingsProvider)
{
this._settingsProvider = settingsProvider;
this._settings = new Lazy<FooSettings>(this.InitializeSettings);
}
private readonly SettingsProvider _settingsProvider;
private readonly Lazy<FooSettings> _settings;
public FooSettings Settings
{
get
{
return this._settings.Value;
}
}
private FooSettings InitializeSettings()
{
var providerSettings = this._settingsProvider.GetSettings("fooSettings");
var fooSettings = new FooSettings(providerSettings[0], providerSettings[1]);
return fooSettings;
}
}
要注册您的FooSettings,您可以使用此注册:
builder.RegisterType<FooSettingsProvider>()
.As<ISettingsProvider<FooSettings>>();
builder.Register(c => c.Resolve<ISettingsProvider<FooSettings>>().Settings)
.As<FooSettings>();