ASP.NET + StructureMap = Epic Win

After running into a lot of testing problems with my current architecture in ASP.NET, I decided that it was time to look into an IoC Framework.  I have heard the marvels of how it makes code so much more isolated and clean (SOLID), but I couldn’t see my code ever getting to this point.  Because this project has a ton of legacy code, there was little incentive to add anything else when it was already so highly coupled.  I needed to take a step back and look at it from a different perspective.

I understood how IoC (Inversion of Control) Frameworks worked and knew how this technique is used, but I didn’t know how I could integrate it in my application.  Most of my action/service methods were static classes that instantiated new objects to return what I needed.

Here’s an example:

On the member page, there is a list of upcoming conferences that calls this code:

Public Class ConferenceService    

	Public Shared Function GetUpcomingConferences(ByVal DisplayDate As DateTime) As IList(Of ConferenceEntity)        
		Using repo As New Repository            
			Dim bucket As New RelationPredicateBucket(ConferenceFields.IsActive = True)
            Dim startfilter As New PredicateExpression(ConferenceFields.StartDisplayDate = System.DBNull.Value)            
			startfilter.AddWithOr(ConferenceFields.StartDisplayDate <= DisplayDate)    
			bucket.PredicateExpression.AddWithAnd(startfilter)         

			Dim endfilter As New PredicateExpression(ConferenceFields.EndDisplayDate = System.DBNull.Value)   
			endfilter.AddWithOr(ConferenceFields.EndDisplayDate >= DisplayDate)           
			bucket.PredicateExpression.AddWithAnd(endfilter)          
			Dim sorter As New SortExpression(ConferenceFields.StartDateTimeUtc Or SortOperator.Ascending)    
			Return repo.GetCollection(Of ConferenceEntity)(bucket, sorter).ToList()    
		End Using   
	End Function
	
End Class

I am using LLBLGen (Adapter) as my DAL so the Repository class is responsible for calling a new object to create what LLBLGen calls an EntityCollection.  This is easy to call because all I have to do is call ConferenceService.GetUpcomingConferences(Date.Now()) to get a list of upcoming conference.  This is very hard to test though without using something like Typemock.

In order to start my refactoring to be able to integrate StructureMap, I needed to look at how my ConferenceService was being constructed.  There are 5 constructor calls in this method alone. You can imagine how the rest of the application looks like.

Adding and Setting Up StructureMap

First, download StructureMap from the website.  I downloaded version 2.5.3.  Next was to look how to get StructureMap set up on the web project (found here http://structuremap.sourceforge.net/ConfiguringStructureMap.htm).  I had to use for VB and lambdas are tricky so this is how the Bootstrapper was defined:

Imports StructureMap
Imports StructureMap.Configuration.DSL

Public Class Bootstrapper    
	
	Public Shared Sub BootstrapStructureMap()        
		ObjectFactory.Initialize(AddressOf ConfigStructureMap)    
	End Sub    

	Private Shared Sub ConfigStructureMap(ByVal x As IInitializationExpression)        
		x.AddRegistry(New RepositoryRegistry)    
	End Sub    
	
	Public Class RepositoryRegistry       
		Inherits Registry        
		
		Overrides Protected Sub configure()   
			'Will be used later after we refactor      
			'ForRequestedType(Of IRepository)().TheDefaultIsConcreteType(Of Repository)().CacheBy(Attributes.InstanceScope.Hybrid)   
		End Sub   
		
	 End Class
 End Class

And then, in our Global.asax, on the Application_Start, call the Bootstrapper.BootstrapStructureMap() method. That is all we need for StructureMap config for now.  That will get us started in the right direction.

imageRefactoring

The first refactoring is to Extract an Interface from the Repository class.  If you have a refactoring tool such as Refactor Pro! or Resharper, this is made very easy.  I called mine, IRepository.  This will make the Repository class implement the newly created interface.  We can now start on the ConferenceService.

The next refactoring is to create a constructor for the ConferenceService class that takes an IRepository as a parameter.  This will help us create Constructor Injection.

After we add the parameter, we can remove the code that uses the concrete Repository object.

 Public Class ConferenceService   
	 
	 Private _repo As IRepository    
	 ''' <summary>    
	 ''' Initializes a new instance of the ConferenceService class.    
	 ''' </summary>    
	 ''' <param name="repo"></param>    
	 Public Sub New(ByVal repo As IRepository)        
		_repo = repo    
	 End Sub    
	 
	 Public Function GetUpcomingConferences(ByVal DisplayDate As DateTime) As IList(Of ConferenceEntity)        
		 Dim bucket As New RelationPredicateBucket(ConferenceFields.IsActive = True)        
		 im startfilter As New PredicateExpression(ConferenceFields.StartDisplayDate = System.DBNull.Value)        
		 startfilter.AddWithOr(ConferenceFields.StartDisplayDate <= DisplayDate)        
		 bucket.PredicateExpression.AddWithAnd(startfilter)        
		 Dim endfilter As New PredicateExpression(ConferenceFields.EndDisplayDate = System.DBNull.Value)        
		 endfilter.AddWithOr(ConferenceFields.EndDisplayDate >= DisplayDate)        
		 bucket.PredicateExpression.AddWithAnd(endfilter)        
		 Dim sorter As New SortExpression(ConferenceFields.StartDateTimeUtc Or SortOperator.Ascending)        
		 Return _repo.GetCollection(Of ConferenceEntity)(bucket, sorter).ToList()            
	End Function   
	
 End Class

The next piece of code is back in our Bootstrapper that we have to uncomment. 

'ForRequestedType(Of IRepository)().TheDefaultIsConcreteType(Of Repository)().CacheBy(Attributes.InstanceScope.Hybrid) 

Now, instead of calling the static method as such:

Dim upcomingConf as IList(Of ConferenceEntity) = ConferenceService.GetUpcomingConferences(Date.Now())

We can call it as such:

Dim upcomingConf as IList(Of ConferenceEntity) = new ConferenceService(ObjectFactory.GetInstance(Of IRepository)()).GetUpcomingConferences(Date.Now())

This allows us to decouple the concrete Repository object and allows for testing out our method. We’ll be able to write tests now to cover our legacy code, and allow for more flexible code.


Posted 11-25-2009 10:51 PM by Stephen Wright
Filed under:

[Advertisement]

Comments

bonskijr wrote re: ASP.NET + StructureMap = Epic Win
on 11-26-2009 3:16 AM

Is that a typo on the last code?

_new ConferenceService(..);

or it's a VB.NET specific?

thanks

DaRage wrote re: ASP.NET + StructureMap = Epic Win
on 11-26-2009 9:19 AM

VB.. yuk

Stephen Wright wrote re: ASP.NET + StructureMap = Epic Win
on 11-26-2009 10:38 AM

Yes, that was a typo on the last code snippet.  It's fixed now.

VB may not be popular or well liked, but my application uses it.  And since there are hardly any samples using SM or a lot of other frameworks and controls, I wanted to show that it can be done in VB.  Code in all languages can be made better.

Sanjeev Agarwal wrote Daily tech links for .net and related technologies - November 28-30, 2009
on 11-29-2009 2:27 AM

Daily tech links for .net and related technologies - November 28-30, 2009 Web Development Main Differences

uberVU - social comments wrote Social comments and analytics for this post
on 11-30-2009 9:37 AM

This post was mentioned on Twitter by devlicious: New Blog Post ASP.NET + StructureMap = Epic Win: After running into a lot of testing problems with my current archi... http://bit.ly/6YjcUJ

Nate wrote re: ASP.NET + StructureMap = Epic Win
on 11-30-2009 9:37 AM

Why oh why ...stupid VB.

Payce wrote re: ASP.NET + StructureMap = Epic Win
on 01-24-2010 11:12 PM

Look gang, there are 100's of examples of refactoring code and using S/M in C#.  This is one of the few good examples I've seen for VB.NET.  While I personally wouldn't use VB, it still has a VERY large following.  Most VB.NET write code as if we're still in VB6 days, but Steve shows a great example of using modern OO strategies against an app built in a legacy fashion.  Nice work Steve!

Narazana wrote re: ASP.NET + StructureMap = Epic Win
on 03-23-2010 10:32 AM

Thank you for example in VB.NET. It's so hard to find example in VB.NET with Structure Map + ASP.NET....

This will help me and my friends get started.

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)