Autofac:如何控制内部依赖解析链中的实例注入?
问题:Autofac中控制深层依赖链的DbContext注入
现有类结构
Public Class ProcessRunner Implements IProcessRunner Public Sub New(Command As ICommand) End Sub End Class Public Class Command Implements ICommand Public Sub New(BootStrapper As IBootStrapper) End Sub End Class Public Class BootStrapper Implements IBootStrapper Public Sub New(Releases As IReleases) End Sub End Class Public Class Releases Implements IReleases Public Sub New(Repository As IRepository) End Sub End Class Public Class Repository Implements IRepository Public Sub New(Context As DbContext) End Sub End Class Public Class MsSqlContext Inherits DbContext End Class Public Class SqliteContext Inherits DbContext End Class
初始组件注册
Builder.RegisterType(Of ProcessRunner).As(Of IProcessRunner) Builder.RegisterType(Of BootStrapper).As(Of IBootStrapper) Builder.RegisterType(Of Releases).As(Of IReleases) Builder.RegisterType(Of Command).As(Of ICommand)
Repository与DbContext注册
Dim oSqliteParameter As ResolvedParameter Dim oSqliteAccessor As Func(Of ParameterInfo, IComponentContext, Object) Dim oMsSqlParameter As ResolvedParameter Dim oMsSqlAccessor As Func(Of ParameterInfo, IComponentContext, Object) Dim oSqlPredicate As Func(Of ParameterInfo, IComponentContext, Boolean) oSqliteAccessor = Function(Info, Context) Context.ResolveKeyed(Of DbContext)(NameOf(SqliteContext)) oMsSqlAccessor = Function(Info, Context) Context.ResolveKeyed(Of DbContext)(NameOf(MsSqlContext)) oSqlPredicate = Function(Info, Context) Info.ParameterType = GetType(DbContext) oSqliteParameter = New ResolvedParameter(oSqlPredicate, oSqliteAccessor) oMsSqlParameter = New ResolvedParameter(oSqlPredicate, oMsSqlAccessor) With Builder .RegisterType(Of Repository(Of Dto.Release, Model.Release)). WithParameter(oSqliteParameter). Keyed(Of IRepository(Of Dto.Release, Model.Release))(NameOf(SqliteContext)). As(Of IRepository(Of Dto.Release, Model.Release))() .RegisterType(Of Repository(Of Dto.Release, Model.Release)). WithParameter(oMsSqlParameter). Keyed(Of IRepository(Of Dto.Release, Model.Release))(NameOf(MsSqlContext)). As(Of IRepository(Of Dto.Release, Model.Release))() .RegisterType(Of SqliteContext). InstancePerLifetimeScope. Keyed(Of DbContext)(NameOf(SqliteContext)). As(Of DbContext)() .RegisterType(Of MsSqlContext). InstancePerLifetimeScope. Keyed(Of DbContext)(NameOf(MsSqlContext)). As(Of DbContext)() End With
问题现象
解析ProcessRunner时,内部始终将MsSqlContext注入到Repository中(推测是按字母顺序优先匹配),导致测试时连接生产数据库,测试失败。
尝试过相关解决方案,但无法适配当前的深层依赖链场景。不想为整个依赖链注册两套实例,希望找到更简洁的方式,在解析时指定使用SqliteContext或MsSqlContext,并将这个选择传递到整个依赖层级中,以此控制注入到Releases构造函数的Repository实例。
当前临时解决方案
通过一系列扩展方法实现了功能,但逻辑繁琐:
Friend Module Extensions <Extension> Friend Function ProcessRunner(Of TContext As DbContext)(Instance As ILifetimeScope) As IProcessRunner Return Instance.Resolve(Of IProcessRunner)(Instance.CommandParameter(Of TContext)) End Function <Extension> Friend Function Command(Of TContext As DbContext)(Instance As ILifetimeScope) As ICommand Return Instance.Resolve(Of ICommand)(Instance.BootStrapperParameter(Of TContext)) End Function <Extension> Friend Function BootStrapper(Of TContext As DbContext)(Instance As ILifetimeScope) As IBootStrapper Return Instance.Resolve(Of IBootStrapper)(Instance.ReleasesParameter(Of TContext)) End Function <Extension> Friend Function Releases(Of TContext As DbContext)(Instance As ILifetimeScope) As IReleases Return Instance.Resolve(Of IReleases)(Instance.RepositoryParameter(Of TContext)) End Function <Extension> Friend Function Repository(Of TContext As DbContext)(Instance As ILifetimeScope) As IRepository Return Instance.ResolveKeyed(Of IRepository)(GetType(TContext).Name) End Function <Extension> Private Function RepositoryParameter(Of TContext As DbContext)(Instance As ILifetimeScope) As TypedParameter Return TypedParameter.From(Instance.Repository(Of TContext)) End Function <Extension> Private Function ReleasesParameter(Of TContext As DbContext)(Instance As ILifetimeScope) As TypedParameter Return TypedParameter.From(Instance.Releases(Of TContext)) End Function <Extension> Private Function BootStrapperParameter(Of TContext As DbContext)(Instance As ILifetimeScope) As TypedParameter Return TypedParameter.From(Instance.BootStrapper(Of TContext)) End Function <Extension> Private Function CommandParameter(Of TContext As DbContext)(Instance As ILifetimeScope) As TypedParameter Return TypedParameter.From(Instance.Command(Of TContext)) End Function End Module
调用示例
<Fact> Sub Process_Runner_Should_Have_Correct_Arguments() Dim oProcessRunner As IProcessRunner Using oScope As ILifetimeScope = Me.Container.BeginLifetimeScope ' Arrange ' Act oProcessRunner = oScope.ProcessRunner(Of SqliteContext) ' Assert oProcessRunner.Command.Arguments.Update.Count.Should.Be(4) oProcessRunner.Command.Arguments.Clean.Count.Should.Be(6) End Using End Sub
该方案能正常工作,但过于复杂,希望得到更简洁的改进方案。
内容的提问来源于stack exchange,提问作者InteXX
相关产品推荐
相关产品推荐

