【问题标题】:Problem Implementing StructureMap in VB.Net Conversion of SharpArchitecture在 SharpArchitecture 的 VB.Net 转换中实现 StructureMap 的问题
【发布时间】:2025-12-13 09:35:01
【问题描述】:

我在 VB.Net 环境中工作,最近的任务是创建一个 MVC 环境以用作工作的基础。我决定将最新的 SharpArchitecture 版本(2009 年第 3 季度)转换为 VB,经过一番拉扯后,总体上已经很好了。我遇到了 Castle Windsor 的一个问题,在我的测试控制器的构造函数中引用的自定义存储库接口(位于核心/域项目中)没有被注入具体实现(来自数据项目)。我为此碰壁了,所以基本上决定将 Castle Windsor 换成 StructureMap。

我认为我已经实现了这一点,因为一切都可以编译和运行,并且我的控制器在引用自定义存储库接口时运行正常。现在看来,我已经/或现在无法正确设置我的通用接口(我希望这是有道理的,因为我对这一切都不熟悉)。当我在控制器构造函数中使用 IRepository(Of T) (希望它被注入 Repository(Of Type) 的具体实现)时,我收到以下运行时错误:

“StructureMap 异常代码:202 没有为 PluginFamily SharpArch.Core.PersistenceSupport.IRepository 定义默认实例`1[[DebtRemedy.Core.Page, DebtRemedy.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken =null]],SharpArch.Core,版本=1.0.0.0,文化=中性,PublicKeyToken=b5f559ae0ac4e006"

这是我正在使用的代码摘录(我的项目称为 DebtRemedy)。

我的结构映射注册表类

Public Class DefaultRegistry
    Inherits Registry

    Public Sub New()
        ''//Generic Repositories
        AddGenericRepositories()
        ''//Custom Repositories
        AddCustomRepositories()
        ''//Application Services
        AddApplicationServices()
        ''//Validator
        [For](GetType(IValidator)).Use(GetType(Validator))
    End Sub

    Private Sub AddGenericRepositories()
        ''//ForRequestedType(GetType(IRepository(Of ))).TheDefaultIsConcreteType(GetType(Repository(Of )))
        [For](GetType(IEntityDuplicateChecker)).Use(GetType(EntityDuplicateChecker))
        [For](GetType(IRepository(Of ))).Use(GetType(Repository(Of )))
        [For](GetType(INHibernateRepository(Of ))).Use(GetType(NHibernateRepository(Of )))
        [For](GetType(IRepositoryWithTypedId(Of ,))).Use(GetType(RepositoryWithTypedId(Of ,)))
        [For](GetType(INHibernateRepositoryWithTypedId(Of ,))).Use(GetType(NHibernateRepositoryWithTypedId(Of ,)))
    End Sub

    Private Sub AddCustomRepositories()
        Scan(AddressOf SetupCustomRepositories)
    End Sub

    Private Shared Sub SetupCustomRepositories(ByVal y As IAssemblyScanner)
        y.Assembly("DebtRemedy.Core")
        y.Assembly("DebtRemedy.Data")
        y.WithDefaultConventions()
    End Sub

    Private Sub AddApplicationServices()
        Scan(AddressOf SetupApplicationServices)
    End Sub

    Private Shared Sub SetupApplicationServices(ByVal y As IAssemblyScanner)
        y.Assembly("DebtRemedy.ApplicationServices")
        y.With(New FirstInterfaceConvention)
    End Sub

End Class

Public Class FirstInterfaceConvention
    Implements ITypeScanner

    Public Sub Process(ByVal type As Type, ByVal graph As PluginGraph) Implements ITypeScanner.Process
        If Not IsConcrete(type) Then
            Exit Sub
        End If
        ''//only works on concrete types
        Dim firstinterface = type.GetInterfaces().FirstOrDefault()
        ''//grabs first interface
        If firstinterface IsNot Nothing Then
            graph.AddType(firstinterface, type)
        Else
            ''//registers type
            ''//adds concrete types with no interfaces
            graph.AddType(type)
        End If
    End Sub
End Class

我已经尝试过 ForRequestedType(我认为现在已弃用)和 For. IRepository(Of T) 位于 SharpArch.Core.PersistenceSupport 中。 Repository(Of T) 位于 SharpArch.Data.NHibernate 中。

我的服务定位器类

    Public Class StructureMapServiceLocator
    Inherits ServiceLocatorImplBase
    Private container As IContainer

    Public Sub New(ByVal container As IContainer)
        Me.container = container
    End Sub

    Protected Overloads Overrides Function DoGetInstance(ByVal serviceType As Type, ByVal key As String) As Object
        Return If(String.IsNullOrEmpty(key), container.GetInstance(serviceType), container.GetInstance(serviceType, key))
    End Function

    Protected Overloads Overrides Function DoGetAllInstances(ByVal serviceType As Type) As IEnumerable(Of Object)
        Dim objList As New List(Of Object)
        For Each obj As Object In container.GetAllInstances(serviceType)
            objList.Add(obj)
        Next
        Return objList
    End Function
End Class

我的控制器工厂类

    Public Class ServiceLocatorControllerFactory
    Inherits DefaultControllerFactory

    Protected Overloads Overrides Function GetControllerInstance(ByVal requestContext As RequestContext, ByVal controllerType As Type) As IController
        If controllerType Is Nothing Then
            Return Nothing
        End If

        Try
            Return TryCast(ObjectFactory.GetInstance(controllerType), Controller)
        Catch generatedExceptionName As StructureMapException
            System.Diagnostics.Debug.WriteLine(ObjectFactory.WhatDoIHave())
            Throw
        End Try
    End Function

End Class

我的 global.asax 中的初始化内容

Dim container As IContainer = New Container(New DefaultRegistry)
ControllerBuilder.Current.SetControllerFactory(New ServiceLocatorControllerFactory())

ServiceLocator.SetLocatorProvider(Function() New StructureMapServiceLocator(container))

我的测试控制器

Public Class DataCaptureController
Inherits BaseController

Private ReadOnly clientRepository As IClientRepository()
Private ReadOnly pageRepository As IRepository(Of Page)

Public Sub New(ByVal clientRepository As IClientRepository(), ByVal pageRepository As IRepository(Of Page))
    Check.Require(clientRepository IsNot Nothing, "clientRepository may not be null")
    Check.Require(pageRepository IsNot Nothing, "pageRepository may not be null")
    Me.clientRepository = clientRepository
    Me.pageRepository = pageRepository
End Sub

Function Index() As ActionResult
    Return View()
End Function

当我取出与 IRepository(Of T) 的 pageRepository 相关的所有内容时,上述操作正常。

对此的任何帮助将不胜感激。

【问题讨论】:

  • 很遗憾,我无法帮助您解决问题,但很高兴看到有人知道如何编写好的 VB 代码。 Stack Overflow 上的大多数 VB 问题都让我感到绝望。
  • 恕我直言,您真的可以简化这个问题 - 只需显示您尝试注册失败类型的代码行,并设置几行代码尝试获取该实例通过容器或对象工厂输入。如果注册不起作用,它应该以同样的方式失败。

标签: asp.net-mvc vb.net structuremap ioc-container s#arp-architecture


【解决方案1】:

昨天我在实例化 IRepository(Of MyEntity) 时遇到了类似的问题。

我必须在我的 Scan 委托中声明 y.ConnectImplementationsToTypesClosing(GetType(IRepository(Of ))) 以使 StructureMap 将泛型类型映射到它们的实现。

像这样:

Private Shared Sub SetupCustomRepositories(ByVal y As IAssemblyScanner)
    y.Assembly("DebtRemedy.Core")
    y.Assembly("DebtRemedy.Data")
    y.WithDefaultConventions()
    y.ConnectImplementationsToTypesClosing(GetType(Of ));
End Sub

【讨论】:

    【解决方案2】:

    确保您只创建一个容器。

    我还将 C# 项目从 Castle Windsor 转换为 StructureMap。最初的基于 CW 的项目在 Application_Start()(MVC2 项目)中实例化了一个 Container,并将其传递给配置。我不假思索地保持了同样的方法,有点像你从西班牙语翻译成英语的时候,它同样糟糕。 :)

    我最终创建了第二个 SM 容器。 StructureMap 的容器是静态的,因此总是有一个“在后台”。如果你新建一个容器,你实际上是创建了第二个独立的容器。如果您不小心,您最终有时会使用一个,有时会使用另一个,并且当您知道它已定义时,会在各个点遇到“无默认实例”错误的瘟疫..

    我遇到它的方式是,我最终在代码中乱扔了 WhatDoIHave() 调用,这很幸运,因为我注意到有时我看到了一个已配置的容器(第二个),有时我看到了静态的容器(第一个),尚未配置。不同的 GUID 名称是赠品。

    检查您的 VB 代码中是否发生了同样的情况。

    【讨论】:

      【解决方案3】:

      对此不太熟悉,但看起来它可能没有在容器中注册,或者因为解析器很贪婪,它可能会选择没有注册项的构造函数。下面的 URL 看起来很相似,同样的问题看看... http://learningbyfailing.com/2010/02/structuremap-exception-no-default-instance-defined-for-pluginfamily-iformsauthentication/

      【讨论】:

        最近更新 更多