StructureMap Autowiring с двумя разными экземплярами одного и того же интерфейса - PullRequest
4 голосов
/ 09 января 2011

В последние два дня я изо всех сил старался что-то узнать о StructureMap, используя мой старый проект в качестве конкретного примера реализации.Я постарался максимально упростить свой вопрос.Хотя я буду публиковать свои примеры на vb.net, ответы с примерами на C # также хороши.

Проект включает интерфейсы, называемые IDatabase, которые подключаются к базе данных.Важная часть выглядит следующим образом.

Public Interface IDatabase
    Function Connect(ByVal ConnectionSettings As ConnectionSettings) As Boolean
    ReadOnly Property ConnectionOpen As Boolean
    [... more functions...]
End Interface

Public Class MSSQLConnection
    Implements IDatabase
    Public Function Connect(ByVal ConnectionSettings As ConnectionSettings) As Boolean Implements IDatabase.Connect

       [... Implementation ...]

    End Function

[... more implementations...]
End Class

ConnectionSettings - это структура, содержащая всю информацию, необходимую для подключения к базе данных.

Я хочу один раз открыть соединение с базой данных и использовать его длякаждое соединение в проекте, поэтому я регистрирую экземпляр в ObjectFactory.

dim foo = ObjectFactory.GetInstance(Of MSSQLConnection)()
dim bar as ConnectionSettings
foo.connect(bar)
ObjectFactory.Configure(Sub(x) x.For(Of IDatabase).Use(foo))

До этой части все работало как шарм.Теперь я дошел до того, что у меня есть классы, которым нужен дополнительный экземпляр IDatabase, потому что они подключаются ко второй базе данных.

Public Class ExampleClass
Public Sub New(ByVal SameOldDatabase as IDatabase, ByVal NewDatabase as IDatabase)
[...] Magic happens here [...]
End Sub
End Class

Я хочу, чтобы эта вторая база данных вела себя так же, как и первая.Я хочу, чтобы он использовал конкретный единственный экземпляр и хотел подключить его к другой базе данных, вызывая Connect с другими ConnectionSettings.

Проблема заключается в следующем: хотя я почти уверен, что это каким-то образом возможно (моя первоначальная идеярегистрировал ExampleClass с альтернативными аргументами конструктора), я на самом деле хочу сделать это без регистрации ExampleClass.Вероятно, это требует больше настроек, но я понятия не имею, как это сделать.

Итак, в основном, все сводится к следующему вопросу: как мне сконфигурировать ObjectFactory таким образом, чтобы автопроводка всегда вызывала конструктор собъект Database1 для первого параметра IDatabase и объект Database2 для второго (если он есть?)

1 Ответ

2 голосов
/ 09 января 2011

Вы можете использовать RegistrationConvention и именованный экземпляр для второго соединения.Рассмотрим следующий быстрый и грязный код:

Imports StructureMap.Graph
Imports StructureMap.Configuration.DSL
Imports StructureMap

Public Module Module1

    Public Interface IDatabase
        Property ConString As String
    End Interface

    Public Class MSSQLConnection
        Implements IDatabase
        Public Property ConString() As String Implements IDatabase.ConString
    End Class

    Public Class ExampleClass
        Public Sub New(ByVal SameOldDatabase As IDatabase, ByVal NewDatabase As IDatabase)
            Console.WriteLine(SameOldDatabase.ConString)
            Console.WriteLine(NewDatabase.ConString)
        End Sub
    End Class

    Public Class SecondDatabaseConstructorIsAnotherOne
        Implements IRegistrationConvention

        Public Sub Process(ByVal type As Type, ByVal registry As Registry) Implements IRegistrationConvention.Process
            Dim ctor = type.GetConstructors().FirstOrDefault(Function(c) c.GetParameters().Where(Function(p) p.ParameterType = GetType(IDatabase)).Count = 2)
            If Not ctor Is Nothing Then

                Dim parameter = New List(Of Object)

                Dim second = False

                For Each o In ctor.GetParameters()
                    If o.ParameterType = GetType(IDatabase) AndAlso second Then
                        parameter.Add(ObjectFactory.GetNamedInstance(Of IDatabase)("secondDB"))
                    Else
                        If o.ParameterType = GetType(IDatabase) Then second = True
                        parameter.Add(ObjectFactory.GetInstance(o.ParameterType))
                    End If
                Next

                registry.For(type).Use(Function(context) Activator.CreateInstance(type, parameter.ToArray()))

            End If
        End Sub

    End Class

    Sub Main()

        Dim con1 = New MSSQLConnection() With {.ConString = "ConnectToFirstDatabase"}
        Dim con2 = New MSSQLConnection() With {.ConString = "ConnectToSecondDatabase"}

        ObjectFactory.Initialize(Sub(init)
                                     init.For(Of IDatabase).Use(con1)
                                     init.For(Of IDatabase).Add(con2).Named("secondDB")
                                 End Sub)

        ObjectFactory.Configure(Sub(config)
                                    config.Scan(Sub(scan)
                                                    scan.TheCallingAssembly()
                                                    scan.Convention(Of SecondDatabaseConstructorIsAnotherOne)()
                                                End Sub)
                                End Sub)

        ObjectFactory.GetInstance(Of ExampleClass)()
        Console.ReadLine()
    End Sub

End Module

Вы поймете идею.

...