Web Design, Programming, Tutorials
Setting up Structure Map
StructureMap
If you haven’t heard about dependency injection, it is something you should definitely look into. It can save tons of time when coding.
StructureMap is a dependency injection framework that makes it easy to create new instances of objects and even cache an instance of an object so various references to the object use the same instance. This is very useful with objects such as database connections.
You can download the library from the StructureMap Home Page. The example used in this post is using StructureMap 2.6.1. I’m also using Visual Basic. I had a tough time finding information on how to use StructureMap with Visual Basic, so hopefully, this will help someone else.
Setting Up MVC
When using StructureMap with ASP.NET MVC 1.0, I’ve found it works best if a folder is created in each project; Main, Data, and Service; where the StructureMap files are stored. This keeps them organized and makes them easy to find as you need to update them. A reference to the StructureMap DLL will need to be added to each project as well.
In the main project’s StructureMap folder, the following files are needed:
StructureMapControllerFactory
Imports System.Web.Mvc
Imports StructureMap
Public Class StructureMapControllerFactory
Inherits DefaultControllerFactory
Protected Overrides Function GetControllerInstance(ByVal controllerType As System.Type) As System.Web.Mvc.IController
Return ObjectFactory.GetInstance(controllerType)
End Function
End Class
This class sets up a factory class to get an instance of the StructureMap factory. It will be used to replace MVC’s default controller factory so that StructureMap will be in charge of creating our controllers.
BootStrapper
Imports StructureMap
Imports YourProject.Data
Imports YourProject.Services
Public Class BootStrapper
Public Shared Sub ConfigureStructureMap()
ObjectFactory.Initialize(AddressOf StructureMapRegistry)
End Sub
Private Shared Sub StructureMapRegistry(ByVal x As IInitializationExpression)
x.AddRegistry(New MainRegistry())
x.AddRegistry(New DataRegistry( _ ConfigurationManager.ConnectionStrings("iSeries").ConnectionString, _ ConfigurationManager.ConnectionStrings("Interbase").ConnectionString))
x.AddRegistry(New ServiceRegistry())
x.Scan(AddressOf StructureMapScanner)
End Sub
Private Shared Sub StructureMapScanner(ByVal scanner As StructureMap.Graph.IAssemblyScanner)
scanner.Assembly("YourProjectNamespace")
scanner.Assembly("YourProjectNamespace.Data")
scanner.Assembly("YourProjectNamespace.Services")
scanner.WithDefaultConventions()
End Sub
End Class
This class is where StructureMap is configured. Within the StructureMapRegistry method, each AddRegistry call is made to include each of our project’s registry files, which have yet to be created. We will get to that in a moment, but notice that the DataRegistry is accepting values for connection strings. This is how information can be passed into a class being created by StructureMap when you would like to keep the configuration settings within the Web.config file.
Also, within the StructureMapScanner method, an entry needs to be made to scan each project’s namespace.
MainRegistry
Imports DCS.Data
Imports StructureMap.Configuration.DSL
Public Class MainRegistry
Inherits Registry
Public Sub New()
[For](Of IWebContext)() _
.Use(Of WebContext)()
End Sub
End Class
Each project will have its own registry file where you can specify that Interface-A should create an instance of Class-A. In the example above, I want StructureMap to create an instance of WebContext (from the main project) when it comes across a reference to IWebContext.
In the Data project’s StructureMap folder you will need:
DataRegistry
Imports StructureMap.Configuration.DSL
Imports Spartan.DAO.Database
Public Class DataRegistry
Inherits Registry
Public Sub New(ByVal iSeriesConnectionString As String, ByVal interbaseConnectionString As String)
'Data Connections.
[For](Of YourDataContext)() _
.HybridHttpOrThreadLocalScoped _
.Use(Function() New YourDataContext())
[For](Of DB2Connection)() _
.HybridHttpOrThreadLocalScoped _
.Use(Function() New DB2Connection(iSeriesConnectionString))
[For](Of InterbaseConnection)() _
.HybridHttpOrThreadLocalScoped _
.Use(Function() New InterbaseConnection(interbaseConnectionString))
'Repositories.
[For](Of IShiftRepository)() _
.Use(Of ShiftRepository)()
End Sub
End Class
The DataRegistry is interesting because we are passing in two connection strings from the Web.config file. The first data connection is for Microsoft SQL, the second for DB2 and the third for Interbase. The second and third are using the DB2Connection and InterbaseConnection classes which are home grown database connection class that I wrote. All three of these database connections are being cached by using the .HybridHttpOrThreadLocalScoped property. Using this will make the database cached instance work for both your live program and your unit testing.
The entry under repositories is what all remaining entries would look like within the registry class. Since the data project contains our repositories, they would all be listed here.
And, in the Service project’s StructureMap folder you will need:
ServiceRegistry
Imports StructureMap.Configuration.DSL
Public Class ServiceRegistry
Inherits Registry
Public Sub New()
[For](Of IShiftService)() _
.Use(Of ShiftService)()
End Sub
End Class
The service registry is similar to that of the main project. All service classes found in the service project would be listed here.
Changes to the Global.asax
The last thing to do is setup the Global.asax file to load StructureMap. Make the following changes to the Application_Start method:
Sub Application_Start()
RegisterRoutes(RouteTable.Routes)
'StructureMap
BootStrapper.ConfigureStructureMap()
ControllerBuilder.Current.SetControllerFactory(New StructureMapControllerFactory())
End Sub
Now, the default controller factory used by MVC will be overridden by our StructureMapControllerFactory. When a controller is created, it will now use StructureMap.
So, how do you use this when creating a class? This is the easy part.
StructureMap will use the greediest constructor from your controller, meaning, if you have two constructors, the one with the most parameters will be used. Each parameter references an Interface and sets a class variable for the object. StructureMap uses the registry classes that we setup to map an interface to a real object.
Example Controller
Imports YourProject.Data
Imports YourProject.Services
Imports StructureMap
Public Class ExampleController
Inherits System.Web.Mvc.Controller
Private _shiftService As IShiftService
Private _webContext As IWebContext
Public Sub New( _
ByVal shiftService As IShiftService, _
ByVal webContext As IWebContext)
_shiftService = shiftService
_webContext = webContext
'Initialize service classes.
_shiftSummaryService.Initialize(New ModelStateWrapper(Me.ModelState))
End Sub
...
All that you need to do is create a constructor, pass in all the interface references you need for the controller, then store them in a class variable. If you need to use the ModelState for validation within your service class, the best way I’ve found to do this is use an Initialize function in your service class to pass in the ModelState. This is because the ModelState is not yet created by MVC when the service classes are created by StructureMap.
When StructureMap creates the instance of the ShiftService, it will look at the greediest constructor from that class to create instances for any required parameters. This continues for all classes that are referenced.
Once the solution has been configured to use StructureMap, the only thing you’ll need to maintain will be the registry files as you add new classes and interfaces to your project. Don’t forget to add a registry entry or you will recieve an exception.
about 2 months ago
i am very new to Structure map .I Dont know how to use It.After downloading “StructurrMap” where do i keep it.i knnow it sounds silly but i have no idea.
about 1 month ago
I would suggest creating a folder within your project folder and copying the DLL(s) there. Then, you can add a reference to the project to the file under your project folder. This makes it easy to copy all your required library files with your project if you move it to another computer. You may need to open the properties on the DLL and unblock it if you run into weird errors in Visual Studio.
about 4 weeks ago
Dear Chris,
Could you please provide folks who just started using StructureMap with a full sample working project source code? (email or link to download)
I searched the net and could not find one. Lots of folks talk on how to setup and use with chunks of code and configuration, but no real small working sample. So I can traverse the project and see it in real work.
Thank You,
Sergey
about 2 weeks ago
@Sergey That is a good idea. I have been working in C# lately and would like to recreate this post for that language. I will see if I can find some time to put something together.