在SharpArchitecture的VB.Net转换中实现StructureMap的问题

时间:2010-02-26 21:22:53

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

我在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,Version = 1.0.0.0,Culture = neutral,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。

我的servicelocator类

    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有关的所有内容时,上述工作正常。

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

3 个答案:

答案 0 :(得分:1)

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

我必须在我的扫描委托中声明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

答案 1 :(得分:1)

确保您只创建一个容器。

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

发生的事情是我最终创建了第二个SM容器。 StructureMap的容器是静态的,所以总有一个“在后台”。如果你新建一个容器,你实际上创建了一个独立的第二个容器。如果你不小心,你有时会使用一个,有时候另一个,当你知道它被定义时,会在不同的点上获得“无默认实例”错误的瘟疫。

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

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

答案 2 :(得分:0)

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