autofac中的条件组件注册 [英] conditional component registration in autofac

查看:183
本文介绍了autofac中的条件组件注册的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以根据其他组件的状态有条件地注册一个组件?像这样:

Is it possible to register a component conditionally on an other component's state? Something like:

ContainerBuilder.RegisterConditionally<T>(
  Func<IComponentContext, bool>, 
  Func<IComponentContext, T>);

我发现在autofac的V2之前,可以使用"Register().OnlyIf()"结构,该结构看起来像我在寻找的结构.我希望该功能有条件地覆盖默认注册.

I've found that prior to V2 of autofac one could use a "Register().OnlyIf()" construction that seemed like the one I'm looking for. I would like such feature to conditionally override a default registration.

class CommonRegistrations
{
  public virtual void Register(ContainderBuilder builder)
  {
    builder.Register(ctx => LoadSettings()).As<ISettings>().SingleInstance();
    builder.RegisterType<DefaultFoo>().As<IFoo>();
  }
}

class SpecificRegistrations : CommonRegistrations
{
  public virtual void Register(ContainerBuilder builder)
  {
    base.Register(builder);
    builder.ConditionalyRegister(
      ctx => ctx.Resolve<ISettings>().ReallyUseSpecificFoo, 
      ctx => new SpecificFoo()).As<IFoo>();
  }
}

...

var builder = new ContainerBuilder();
var registrations = new SpecificRegistrations();
registrations.Register(builder);
var container = builder.Build();
IFoo foo = container.Resolve<IFoo>();

根据ISettings.ReallyUseSpecificFoo的foo将是DefaultFoo的实例,或者是SpecificFoo的实例.

The foo will be according to ISettings.ReallyUseSpecificFoo either instance of DefaultFoo or instance of SpecificFoo.

谢谢.

推荐答案

无法根据容器内容在容器级别执行条件注册.问题在于您需要解决以确定容器中已注册的内容,然后从技术上可能会影响您是否首先要注册该内容.鸡/蛋循环依赖问题.

There is no way to perform conditional registration at the container level based on container contents. The trouble is that you would need to resolve something in the container in order to determine what gets registered in the container, which then could technically affect whether you wanted to register the thing in the first place. Chicken/egg circular dependency problem.

但是,您可以有条件地将其注册到嵌套的生存期范围中.大多数集成点(例如ASP.NET)解决了嵌套的生存期范围之外(例如HTTP-request-length生存期范围).您可以将事件动态地注册到嵌套的生命周期范围中,这可能会解决您的问题.

You can, however, register things conditionally into nested lifetime scopes. Most integration points (like ASP.NET) resolve out of nested lifetime scopes (like an HTTP-request-length lifetime scope). You can register things on the fly into nested lifetime scopes and that might solve your problem.

var builder = new ContainerBuilder();
builder.Register(ctx => LoadSettings()).As<ISettings>().SingleInstance();
builder.RegisterType<DefaultFoo>().As<IFoo>();
var container = builder.Build();

var settings = container.Resolve<ISettings>();
using(var scope =
  container.BeginLifetimeScope(b => {
    if(settings.ReallyUseSpecificFoo)
    {
      b.RegisterType<SpecificFoo>().As<IFoo>();
    }
  })
{
  // Resolve things from the nested lifetime scope - it will
  // use the overrides. This will get the SpecificFoo if the
  // configuration setting is true.
  var foo = scope.Resolve<IFoo>();
}

您还有另一个选择,就是使注册成为lambda.这可能会使注册本身更加复杂,但这是您可以考虑的选择.

Another option you have is to make the registration a lambda. It might make the registration itself more complex but it's an option you could consider.

var builder = new ContainerBuilder();
builder.Register(ctx => {
    var settings = ctx.Resolve<ISettings>();
    if(settings.ReallyUseSpecificFoo)
    {
      return new SpecificFoo();
    }
    return new DefaultFoo();
  }).As<IFoo>();

如果手动构建没有吸引力,您也可以通过Autofac.

If manual construction there isn't appealing, you could pass it through Autofac, too.

var builder = new ContainerBuilder();
// Register the IFoo types - but NOT "As<IFoo>"
builder.RegisterType<DefaultFoo>();
builder.RegisterType<SpecificFoo>();
// In the lambda use Resolve<T> to get the instances.
builder.Register(ctx => {
    var settings = ctx.Resolve<ISettings>();
    if(settings.ReallyUseSpecificFoo)
    {
      return ctx.Resolve<SpecificFoo>();
    }
    return ctx.Resolve<DefaultFoo>();
  }).As<IFoo>();

另一种选择是在构建后更新现有容器.在这种情况下,通过实际构建容器,使用该容器并在此之后更改注册来避免出现鸡/蛋的情况.

Yet another option is to update an existing container after being built. In this case, you avoid the chicken/egg scenario by actually building the container, using it, and changing registrations after the fact.

var builder = new ContainerBuilder();
builder.Register(ctx => LoadSettings()).As<ISettings>().SingleInstance();
builder.RegisterType<DefaultFoo>().As<IFoo>();
var container = builder.Build();

var settings = container.Resolve<ISettings>();
if(settings.ReallyUseSpecificFoo)
{
  var updater = new ContainerBuilder();
  updater.RegisterType<SpecificFoo>().As<IFoo>();
  updater.Update(container);
}

最后,您可以考虑XML配置.鉴于注册取决于某种配置设置,因此您可以考虑使用

Finally, you might consider XML configuration. Given the registration is dependent on some sort of configuration setting, you might consider using Autofac's XML configuration support. That way, instead of trying to resolve something out of an un-built container to conditionally register something else, you could just specify the right thing to register using the XML configuration and register the correct thing the first time.

这篇关于autofac中的条件组件注册的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆