1

我正在使用 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

以及另一个程序集 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))

谢谢

4

1 回答 1

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);

这样类型解析就可以工作了。(标记接口也不是世界上最好的模式,但它可以说比将事物的单个实现与特定的消费类型联系起来更好。)

于 2012-06-13T16:11:21.757 回答