我正在使用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))
由于
答案 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);
这样类型分辨率就可以了。 (标记界面也不是世界上最好的模式,但它可能比将各个事物的实现与特定的消费类型联系起来更好。)