StructureMap Autowiring with two different instances of the same interface
For the last two days, i tried my best to learn something about StructureMap, using an old project of mine as an concrete implementation example. I tried to simplify my question as much as possible. While i will post my examples in vb.net, answers with examples in C# are also okay.
The project includes an interfaces called IDatabase which connects itself to a Database. The important part looks like this.
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 is a structure that has all the information needed to connect to a Database.
I want to open the Database Connection once and use it for every single connection in the project, so i register a instance in the ObjectFactory.
dim foo = ObjectFactory.GetInstance(Of MSSQLConnection)()
dim bar as ConnectionSettings
foo.connect(bar)
ObjectFactory.Configure(Sub(x) x.For(Of IDatabase).Use(foo))
Up until this part, everything works like a charm. Now, i get to a point where i hav e classes that need an additional instance of IDatabase because they connect to a second database.
Public Class ExampleClass
Public Sub New(ByVal SameOldDatabase as IDatabase, ByVal NewDatabase as IDatabase)
[...] Magic happens here [...]
End Sub
End Class
I want this second IDatabase to behave much like the first one. I want it to use a concrete, single instance and want to connect it to a different database invoking Connect with a different ConnectionSettings.
The problem is: While i'm pretty sure it's somewhow possible, (my initial idea was registering ExampleClass with alternative constructor arguments), i actually want to do it without registering ExampleClass. This probably involves more configuration, but i have no idea how to do it.
So, basically, it comes down to this question: How do i configurate the ObjectFactory in a way that the autowiring always invokes the constructor with object Database1 for the first IDatabase parameter and object Database2 for the 开发者_开发问答second one (if there is one?)
You could use a RegistrationConvention and a named instance for the second connection. Consider the following quick'n'dirty code:
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
You'll get the idea.
精彩评论