Autofac - 从注册的程序集中解析特定的实现

时间:2012-06-13 06:50:14

标签: vb.net autofac

我正在使用Autofac,想要解决当前程序集的正确实现

我有一个DataContextFactory接口和类:

Public Interface IDataContextFactory
  Inherits IDisposable

  Function GetDataContext() As IDataContext

End Interface

和接口的实现

Public Class CDataContextFactory
  Implements IDataContextFactory

  Private m_oDbContext As IDataContext

  Public Sub New(ByVal i_oDbContext As IDataContext)
    m_oDbContext = i_oDbContext
  End Sub

  Public Function GetDataContext() As CoreData.IDataContext Implements CoreData.IDataContextFactory.GetDataContext
    Return m_oDbContext
  End Function

End Class

所以现在我在每个注册的程序集中都有不同的IDataContext实现。例如,我有一个名为ReportData的程序集,其中包含数据上下文

Public Class CReportDataContext
  Inherits DbContext
  Implements IDataContext

    ---
End Class

还有其他Assembly CommonData中的一个实现

Public Class CFacadeDataContext
  Implements IDataContext

    ---
End Class

然后我在每个程序集中都有我的IRepository的实现。例如

Public MustInherit Class CBaseReadRepository(Of T As {IEntity, Class})
  Implements IReadRepository(Of T)

  Private m_oDataContextFactory As IDataContextFactory
  Private m_oDataContext As IDataContext

  Protected ReadOnly m_oObjectDataSet As CQuery(Of T)

  Public Sub New(ByVal i_oDataContextFactory As IDataContextFactory)
    m_oDataContextFactory = i_oDataContextFactory
    m_oObjectDataSet = DataContext.ObjectDataSet(Of T)()
  End Sub

    ----
End Class

那么如何解决DataContextFactory将解决Assembly ReportData中的CReportDataContext和Assembly CommonData中的CFacadeDataContext

这是我的ContainerBuilder注册:

Dim builder As New ContainerBuilder()

Dim oData = Assembly.Load("ReportData")
builder.RegisterAssemblyTypes(oData).Where(Function(t) t.Name.EndsWith("DataContext")).As(Of IDataContext) _
  .AsImplementedInterfaces.SingleInstance

oData = Assembly.Load("CommonData")
builder.RegisterAssemblyTypes(oData).Where(Function(t) t.Name.EndsWith("DataContext")) _
  .AsImplementedInterfaces().SingleInstance

builder.RegisterAdapter(Of IDataContext, IDataContextFactory)(Function(x) New CDataContextFactory(x))

由于

1 个答案:

答案 0 :(得分:1)

Autofac没有内置支持这种用例。通常建议您尝试不将特定实现与消费者绑定,因为这会破坏整个IoC模式 - 您也可以在课堂上“新建”您需要的依赖类型而不是注入它

如果绝对必须将它们绑在一起,那么您只有几个选项。两者都不漂亮,两者都要求你改变注册方式 - 你可能无法像现在那样进行RegisterAssemblyTypes组装扫描。

首先,您可以使用命名注册。当您注册IDataContext时,请为其命名。注册消耗类时,告诉构建器您希望使用哪个命名实例。

builder.RegisterType<MyDataContext>().Named<IDataContext>("some-name");
var contextParam = ResolvedParameter.ForNamed<IDataContext>("some-name");
builder.RegisterType<MyConsumer>().As<IConsumer>().WithParameter(contextParam);

其次,您可以为消费者注册表达式而不是类型

builder.Register(c => new Consumer(new SomeContext())).As<IConsumer>();

最后,你可以创建一个特殊的模块,它可以确定消费者来自哪个程序集,并尝试将其与相应的IDataContext匹配。这更“自动”,但要复杂得多。存根可能如下所示:

public class DataContextModule : Autofac.Module
{
  protected override void AttachToComponentRegistration(
    IComponentRegistry componentRegistry,
    IComponentRegistration registration)
  {
    registration.Preparing += OnComponentPreparing;
  }

  public static void OnComponentPreparing(object sender, PreparingEventArgs e)
  {
    Type typeBeingResolved = e.Component.Activator.LimitType;
    // TODO: Do some reflection to determine if the type takes an IDataContext
    // in the constructor. If it doesn't, bail. If it does...

    var parameter = new ResolvedParameter(
      (p, i) => p.ParameterType = typeof(IDataContext),
      (p, i) => {
        // TODO: Use i (the IComponentContext for the resolution)
        // to locate the right IDataContext from the list of registrations,
        // resolve that one, and return it so it can be used in
        // constructing the consumer object.
      });
  }
}

就像我说的那样,不漂亮。

如果您有能力影响您的设计,那么制作标记界面可能会更容易,例如:

public interface ICoreDataContext : IDataContext { }

然后在构造函数中使用特定的接口:

public SomeClass(ICoreDataContext context);

这样类型分辨率就可以了。 (标记界面也不是世界上最好的模式,但它可能比将各个事物的实现与特定的消费类型联系起来更好。)