流畅配置多个注册

时间:2011-12-22 18:44:37

标签: c# autofac

我有两个应该一起注册的对象,并且还共享相同的生命期范围。我想提供一个注册扩展来封装这个并保持注册流畅性,但我需要一些帮助。这是我所处的情况:

public static IRegistrationBuilder<?, ?, ?> 
  RegisterChannel<T>(this ContainerBuilder builder, Func<IComponentContext, ChannelFactory<T>> @delegate)
{
  // channelfactory and sharedchannel should have same lifetime configuration
  var channelfactoryreg = builder.Register(c => @delegate(c));
  var sharereg = builder.RegisterType<Wcf.SharedChannel<T>>();

  // is it possible to combine them and return?
  return ???;
}

如何填写空白以便我可以写(例如)builder.RegisterTwo().SingleInstance()?是否可以直接或间接“联合”两个IRegistrationBuilderTLAR对象,以便配置结果可以配置所有基础注册,还是有另一种方法可以执行此操作?

更一般地说:是否有一个用于使用Autofac内部构件的底漆?

感谢您的时间。

3 个答案:

答案 0 :(得分:0)

您应该使用模块来封装有意义的注册。

恕我直言,您应该在两次注册时都致电.SingleInstance()。如果它们是两个服务,则应配置两次。如果他们在注册时共享更多共性,您可以使用Assembly Scanning注册它们。

答案 1 :(得分:0)

我发现我越来越多地使用IRegistrationSource接口将任何相关注册分组在一起。在您的情况下,它们将使您能够对任意类型的集合使用相同的注册码:

public class MyRegistrationSource : IRegistrationSource
{
    /// <summary>
    /// Gets a value indicating whether the registrations provided by this source are 1:1 adapters on top
    /// of other components (I.e. like Meta, Func or Owned.)
    /// </summary>
    public bool IsAdapterForIndividualComponents
    {
        get
        {
            return false;
        }
    }

    /// <summary>
    /// Retrieve registrations for an unregistered service, to be used
    /// by the container.
    /// </summary>
    /// <param name="service">The service that was requested.</param>
    /// <param name="registrationAccessor">A function that will return existing registrations for a service.</param>
    /// <returns>
    /// Registrations providing the service.
    /// </returns>
    public IEnumerable<IComponentRegistration> RegistrationsFor(
        Service service, Func<Service, IEnumerable<IComponentRegistration>> registrationAccessor)
    {
        var swt = service as IServiceWithType;
        if (swt != null)
        {
            // Register requested service types that pass some test or other
            if (swt.ServiceType.HasAttribute<SomeAttribute>(true) ||
                typeof(SomeType).IsAssignableFrom(swt.ServiceType))
            {
                var registration = RegistrationBuilder.ForType(swt.ServiceType)
                    .InstancePerDependency()
                    .CreateRegistration();
                yield return registration;
            }
        }
    }
}

答案 2 :(得分:0)

天哪,我讨厌回答我自己的问题,但所有建议的替代方案似乎都是非常复杂的。尼克的评论最接近参与,但只是成功地吓跑了我的Autofac内部完全;)。我调查过,但这对我的情况来说太过分了。

我最终分裂了差异(正如我在上面的评论中暗示的那样),放弃了流畅的界面,但仍允许通过接受方法本身的配置来灵活地继续注册:

    public static void RegisterSharedChannel<T>(this ContainerBuilder builder, Func<IComponentContext, ChannelFactory<T>> @delegate, 
        Action<Autofac.Builder.IRegistrationBuilder<object, Autofac.Builder.IConcreteActivatorData, Autofac.Builder.SingleRegistrationStyle>> config)
    {
        builder.Register(c => c.Resolve<Wcf.ISharedChannel<T>>().GetChannel()).ExternallyOwned();
        //would be really nice to be able to retain the fluency of the interface, but: http://stackoverflow.com/questions/8608415/fluent-configuration-of-multiple-registrations
        //this should suffice for now...
        var facreg = builder.Register(c => @delegate(c));
        var sharereg = builder.RegisterType<Wcf.SharedChannel<T>>().AsImplementedInterfaces();
        config(facreg);
        config(sharereg);
    }

调用语法不是很漂亮(例如:

builder.RegisterSharedChannel(c => BuildChannelFactory(...), r => r.SingleInstance());

但所有(大部分?)的灵活性仍然存在。