You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 11:37:04