Autofac 注册 IEnumerable 和个人来解决它们
Autofac register IEnumerable and individuals to resolve them all
我们都知道您可以注册多个实例并使用 Autofac 解决它们
builder.RegisterType<Foo1>().As<IFoo>();
builder.RegisterInstance(new Foo2("something")).As<IFoo>();
builder.RegisterInstance(new Foo2("another")).As<IFoo>();
//and finally
var foos = ctx.Resolve<IEnumerable<IFoo>>();
现在我必须注册一些 foos 如下:
builder.Register(ctx =>{
var factory = ctx.Resolve<IFooFactory>();
var allTheFoos = config.FooConfigs.Select(fooConfig => factory.CreateFoo(fooConfig));
return allTheFoos;
}).As<IEnumerable<IFoo>>();
这仍然有效,但我认为这不是正确的方法。
除此之外,我还想补充一个IFoo
的额外注册
builder.RegisterInstance(new Foo2("this one")).As<IFoo>();
如果我现在解析 IEnumerable,我会将集合显式注册为 IEnumerable,但我需要它还包含 Foo2("this one");
//contains allTheFoos, but not Foo2("this one");
var foos = ctx.Resolve<IEnumerable<IFoo>>();
注册本身无法合并,因为它们出于某种原因位于不同的模块中。我想我需要单独注册工厂创建的 foos,但这需要在 Register 方法(或等效方法)中,因为我需要能够首先解析工厂本身。我希望是这样的:
builder.Register(ctx => /* generate foos*/).AsMultiple<IFoo>();
编辑:基于答案
public class BotRegistrationSource : IRegistrationSource
{
private readonly IConfiguration _config;
public BotRegistrationSource(IConfiguration config)
{
_config = config;
}
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service,
Func<Service, IEnumerable<ServiceRegistration>> registrationAccessor)
{
var swt = service as IServiceWithType;
if (!(swt?.ServiceType.IsAssignableTo<IBot>() ?? false))
{
return Enumerable.Empty<IComponentRegistration>();
}
return _config.GetSection("Bots")
.GetChildren()
.Select(c =>
new ComponentRegistration(
Guid.NewGuid(),
new DelegateActivator(swt.ServiceType, (componentContext, _) =>
{
var botFactory = componentContext.Resolve<IBotFactory>();
var config = botFactory.CreateConfig();
c.Bind(config);
var bot = botFactory.Create(config);
bot.Enable();
return bot;
}),
new CurrentScopeLifetime(),
InstanceSharing.None,
InstanceOwnership.OwnedByLifetimeScope,
new[] { service },
new Dictionary<string, object>()));
}
public bool IsAdapterForIndividualComponents => false;
}
我想你要看的是a registration source. Registration sources are a way to do exactly what you want - provide one or more components to the container when a service is requested. The documentation has an example。
我们都知道您可以注册多个实例并使用 Autofac 解决它们
builder.RegisterType<Foo1>().As<IFoo>();
builder.RegisterInstance(new Foo2("something")).As<IFoo>();
builder.RegisterInstance(new Foo2("another")).As<IFoo>();
//and finally
var foos = ctx.Resolve<IEnumerable<IFoo>>();
现在我必须注册一些 foos 如下:
builder.Register(ctx =>{
var factory = ctx.Resolve<IFooFactory>();
var allTheFoos = config.FooConfigs.Select(fooConfig => factory.CreateFoo(fooConfig));
return allTheFoos;
}).As<IEnumerable<IFoo>>();
这仍然有效,但我认为这不是正确的方法。 除此之外,我还想补充一个IFoo
的额外注册builder.RegisterInstance(new Foo2("this one")).As<IFoo>();
如果我现在解析 IEnumerable,我会将集合显式注册为 IEnumerable,但我需要它还包含 Foo2("this one");
//contains allTheFoos, but not Foo2("this one");
var foos = ctx.Resolve<IEnumerable<IFoo>>();
注册本身无法合并,因为它们出于某种原因位于不同的模块中。我想我需要单独注册工厂创建的 foos,但这需要在 Register 方法(或等效方法)中,因为我需要能够首先解析工厂本身。我希望是这样的:
builder.Register(ctx => /* generate foos*/).AsMultiple<IFoo>();
编辑:基于答案
public class BotRegistrationSource : IRegistrationSource
{
private readonly IConfiguration _config;
public BotRegistrationSource(IConfiguration config)
{
_config = config;
}
public IEnumerable<IComponentRegistration> RegistrationsFor(Service service,
Func<Service, IEnumerable<ServiceRegistration>> registrationAccessor)
{
var swt = service as IServiceWithType;
if (!(swt?.ServiceType.IsAssignableTo<IBot>() ?? false))
{
return Enumerable.Empty<IComponentRegistration>();
}
return _config.GetSection("Bots")
.GetChildren()
.Select(c =>
new ComponentRegistration(
Guid.NewGuid(),
new DelegateActivator(swt.ServiceType, (componentContext, _) =>
{
var botFactory = componentContext.Resolve<IBotFactory>();
var config = botFactory.CreateConfig();
c.Bind(config);
var bot = botFactory.Create(config);
bot.Enable();
return bot;
}),
new CurrentScopeLifetime(),
InstanceSharing.None,
InstanceOwnership.OwnedByLifetimeScope,
new[] { service },
new Dictionary<string, object>()));
}
public bool IsAdapterForIndividualComponents => false;
}
我想你要看的是a registration source. Registration sources are a way to do exactly what you want - provide one or more components to the container when a service is requested. The documentation has an example。