当构造函数注入的参数在配置和运行时已知时,从 AutoFac 获取 class 实例的最佳方法是什么
What is the best way to get instance of a class from AutoFac when constructor injection has parameters known at configuration and runtime
我找到了两个与我的问题很接近的相关帖子,但仍然没有回答我正在寻找的内容。
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 容器的应用程序,运行 遇到以下问题。我有 classes 我在启动时向 AutoFac 注册,但一些构造函数参数仅在运行时才知道。我做了一个样本来展示我的意图。注释显示代码中我想要检索 class 实例并在此时注入一些配置数据的位置。
其背后的想法是将通用设置提供程序的实现与某些 classes 的配置分开。配置应从设置提供程序 (ISettingsProvider) 中检索,转换为 class 相关设置 class (FooSettings),然后在创建时注入 class (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
{
}
}
你可以有一个 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>();
当我需要将运行时值作为依赖项注入时,我总是使用 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>();
我找到了两个与我的问题很接近的相关帖子,但仍然没有回答我正在寻找的内容。
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 容器的应用程序,运行 遇到以下问题。我有 classes 我在启动时向 AutoFac 注册,但一些构造函数参数仅在运行时才知道。我做了一个样本来展示我的意图。注释显示代码中我想要检索 class 实例并在此时注入一些配置数据的位置。
其背后的想法是将通用设置提供程序的实现与某些 classes 的配置分开。配置应从设置提供程序 (ISettingsProvider) 中检索,转换为 class 相关设置 class (FooSettings),然后在创建时注入 class (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
{
}
}
你可以有一个 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>();
当我需要将运行时值作为依赖项注入时,我总是使用 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>();