Try our conversational search powered by Generative AI!

Stefan Forsberg
Mar 30, 2010
  10756
(0 votes)

Using StructureMap to work with IDataFactoryFacade

Since I started to write this post Joel Abrahamsson has written a great introduction to what IoC is which rendered the beginning part of my post more or less redundant. So if you’re not familiar with terms like DI (dependency injection) and IoC (Inversion of Controll) I suggest you go there and read his post. Also I’m new to this so I may misuse some concepts and be slightly confused about others.

For this post lets assume we have this simple but oh so useless class:

   1: public class WriteChildrenToStartPageCount
   2: {
   3:     public WriteChildrenToStartPageCount()
   4:     {
   5:     }
   6:  
   7:     public void Write()
   8:     {
   9:         var children = DataFactory.Instance.GetChildren(PageReference.StartPage).Count;
  10:         HttpContext.Current.Response.Write("Children: " + children);
  11:     }
  12: }

Now some cool Alt.Net guy comes along and tells us that working directly against DataFactory is not a very good idea for many reasons. They will probably give you quite the talk about using HttpContext and working with WebForms too, but that’s beside the point.

 

Using constructor injection

Our friend new says that our class shouldn’t be responsible for finding it’s dependency to the DataFactory but rather being told about it. So let’s rewrite our class to do just that.

   1: public class WriteChildrenToStartPageCountV2
   2: {
   3:     private readonly EPiAbstractions.IDataFactoryFacade dataFactoryFacade;
   4:  
   5:     public WriteChildrenToStartPageCountV2(EPiAbstractions.IDataFactoryFacade dataFactoryFacade)
   6:     {
   7:         this.dataFactoryFacade = dataFactoryFacade;
   8:     }
   9:  
  10:     public void Write()
  11:     {
  12:         var children = dataFactoryFacade.GetChildren(PageReference.StartPage).Count;
  13:         HttpContext.Current.Response.Write("Children: " + children);
  14:     }
  15: }

Our class now takes the class to use in its constructor (this is called constructor injection). The class can now be more easily be tested since we can either create our own class that implements the interface or simply mock it. Plus this loosely coupled code make you feel all warm on the inside.

Lets say that we want to call this class on our start page, like this:

   1: public partial class Default : TemplatePage
   2: {
   3:  
   4:     protected override void OnLoad(System.EventArgs e)
   5:     {
   6:         base.OnLoad(e);
   7:  
   8:         Service.WriteChildrenToStartPageCountV2 write = 
   9:             new EPiServer.Service.WriteChildrenToStartPageCountV2(EPiAbstractions.DataFactoryFacade.Instance);
  10:         write.Write();
  11:     }
  12: }

That’s not too much of a hassle, but since we’re creating a whole site we discover that we want to send in that class every time we come across the IDataFactoryFacade interface, it gets a bit tedious. And if we ever wanted to change the concrete class we would have to find every usage of that class and change it which, while easy using a search and replace, feels kind of smelly.

 

Using StructureMap

StructureMap is an IoC (Inversion of Control) tool that solves this problem. Please note I’m using a slightly old version still (2.5.2) so the syntax (or rather the method names) has changed a bit in the newer versions.

We’re going to use StrucutreMap to configure our app to always EPiAbstractions.DataFactoryFacade.Instance whenever an interfaces of type EPiAbstractions.IDataFactoryFacade is requested. We’ll put this code in the Application_Start method in global.asax (after adding a reference to the StructureMap dll).

   1: ObjectFactory.Initialize(x =>
   2: {
   3:     x.ForRequestedType<EPiAbstractions.IDataFactoryFacade>()
   4:         .TheDefault.IsThis(EPiAbstractions.DataFactoryFacade.Instance);
   5: }
   6: );

This code does exactly what it looks to do, it informs StructureMap to use EPiAbstractions.DataFactoryFacade.Instance whenever the type EPiAbstractions.IDataFactoryFacade is requested. So now we’re going to be asking StrucutreMap to give us the object we want and it will magically resolve all our dependencies for us.

   1: Service.WriteChildrenToStartPageCountV2 write = 
   2:     ObjectFactory.GetInstance<EPiServer.Service.WriteChildrenToStartPageCountV2>();
   3: write.Write();

Notice that we don’t have to inform the constructor of WriteChildrenToStartPageCountV2 which class to use for IDataFactoryFacade. What we’re doing here is using StructureMap and it’s ObjectFactory as a Service Locator to resolve the dependencies we might have.

Now if we ever wanted to change which concrete class to use we only have to change the code in one place.

 

Auto Wiring

While the above method works constantly calling ObjectFactory.GetInstance everytime we need IDataFactoryFacade is actually considered somewhat of an IoC anti-patterns. What you want is to have as few explicit calls to GetInstance as you can in your application.

Most (if not all) of the various IoC-containers have a concept of auto wiring, that is to figure out dependencies amongst classes. To exemplify this say that we have these classes

   1: public class SomeExecutor
   2: {
   3:     public SomeExecutor(IValidator validator)
   4:     {
   5:         validator.Validate();
   6:     }
   7: }
   8:  
   9: public class Validator : IValidator
  10: {
  11:     public IRepository Repository { get; set; }
  12:  
  13:     public Validator(IRepository repository) { }
  14:  
  15:     public void Validate()
  16:     {
  17:         Repository.Save();
  18:     }
  19: }
  20:  
  21: public class Repository : IRepository
  22: {
  23:     public void Save()
  24:     {
  25:     }
  26: }

So SomeExecutor has a dependency to IValidator and the concrete class we’re using for that (setup using StrucutreMap config as above) has a dependency to the IRepository. What happens when we do a GetInstance<SomeExecutor> is that StructureMap will looking at the fattest constructor (as in most parameters) and notice that we want a class that implements IValidator. It checks it’s config and find that we want to use the class Validator. This class fattest constructor in its turn wants a IRepository and so on and so on. So even though we only ask for the class at the bottom of the dependency chain StrucutreMap resolves all the dependencies for us and that’s what auto wiring is all about.

If we had been using MVC instead of WebForms this would have been simple to use because you can control the creation of all controls using your own controller factory. WebForms unfortunately has no similar thing for controlling the creation of a System.Web.UI.Page so we have to use a little trick called Setter injections here. Bare with me.

 

One approach to using StructureMap in WebForms

First we create a simple front end interface that has a property of type IDataFactoryFacade. The class that implements the interface takes this dependency via constructor injection like this

   1: public interface IFrontEndService
   2: {
   3:     EPiAbstractions.IDataFactoryFacade DataFactoryFacade { get; set; }
   4: }
   5:  
   6: public class FrontEndService : IFrontEndService
   7: {
   8:     public EPiAbstractions.IDataFactoryFacade DataFactoryFacade { get; set; }
   9:  
  10:     public FrontEndService(EPiAbstractions.IDataFactoryFacade DataFactoryFacade)
  11:     {
  12:         this.DataFactoryFacade = DataFactoryFacade;
  13:     }
  14: }

 

We then create a class that inherits from EPiServers TemplatePage.

   1: public class TemplatePage : EPiServer.TemplatePage
   2: {
   3:     public Abstractions.IFrontEndService FrontEndService { get; set; }
   4:  
   5:     protected override void OnLoad(EventArgs e)
   6:     {
   7:         base.OnLoad(e);
   8:  
   9:         ObjectFactory.BuildUp(this);
  10:     }
  11: }

 

This class has a property of type IFrontEndService and on line 9 some magic happens. To understand what’s going on let’s take a look on how StructureMap is configured.

   1: ObjectFactory.Initialize(x =>
   2: {
   3:     x.ForRequestedType<Abstractions.IFrontEndService>()
   4:         .TheDefaultIsConcreteType<Abstractions.FrontEndService>();
   5:  
   6:     x.ForRequestedType<EPiAbstractions.IDataFactoryFacade>()
   7:         .TheDefault.IsThis(EPiAbstractions.DataFactoryFacade.Instance);
   8:  
   9:     x.SetAllProperties(y => y.OfType<Abstractions.IFrontEndService>());
  10: }
  11: );

Line 3 – 7 is the same way of telling StructureMap which classes to use like we’ve seen above. Line 9 informs it that whenever it comes across a property of type Abstractions.IFrontEndService it should set it’s value. It will look in the config and see that it should set the property to the concrete class FrontEndService which in its turn has a dependency to IDataFactoryFacade. The ObjectFactory.BuildUp(this); (line 9 in the code for TemplatePage) is the line that will activate the setting of the properties setup using SetAllProperties.

Now let’s change our code on the start page to inherit from this TemplatePage instead of EPiServers. We now have access to a FrontEndService property which in turn has a property for our DataFactoryFacade.

   1: public partial class Default : UI.TemplatePage
   2: {
   3:  
   4:     protected override void OnLoad(System.EventArgs e)
   5:     {
   6:         base.OnLoad(e);
   7:  
   8:         Service.WriteChildrenToStartPageCountV2 write
   9:             = new EPiServer.Service.WriteChildrenToStartPageCountV2(FrontEndService.DataFactoryFacade);
  10:             
  11:         write.Write();
  12:     }
  13: }

 

Conclusion

As you notice here I’m still passing in the DataFactoryFacade property to the class WriteChildrenToStartPageCountV2. This is because this class isn’t automatically wired up because we haven’t told StructureMap how and where to do that. But I’m quite happy to pass the property from the FrontEndService to the class since that property in it self is only declared and setup in one place.

It would be quite possible to extract an IWriteChildrenToStartPageCount interface from our concrete class and use that instead of our front end service approach. But since I have a feeling that I’m going to be using the DataFactoryFacade all over the application it can be nice to have it setup on the page that all EPiServer pages inherit from. It’s also quite likely that we’ll be adding other dependencies that’s nice to have available, some ILogger for instance.

The next step is to remove the dependency to HttpContext (since this is null outside of a web-context) in the Write method of the WriteChildrenToStartPageCountV2 but this is left as an exercise for the reader. ^^

Mar 30, 2010

Comments

Sep 21, 2010 10:33 AM

We are currently looking at introducing an IDataFactory interface and adding new constructor and static method overloads to classes that use DataFactory.Instance to take an IDataFactory instead.

Paul Smith
/ Paul Smith

Please login to comment.
Latest blogs
Join the Content Recommendations Work Smarter webinar May 8th 16.00-16.45 CET with expert Aidan Swain

Learn more about Content Recommendations, with Optimizely’s very own Senior Solutions consultant, Aidan Swain . He will discuss best practices and...

Karen McDougall | Apr 12, 2024

Plugin for Identifying and Bulk Deleting Orphaned Missing Properties in Optimizely

I am aware that the Optimizely World community has extensively discussed this topic, with numerous solutions and code snippets available to help...

Adnan Zameer | Apr 11, 2024 | Syndicated blog

Enhancing the Authoring Experience: Extending the LinkItem

The LinkItem field is one of the most demanded properties by the community, allowing editors to effortlessly create and manage links across pages a...

Santiago Morla | Apr 10, 2024 | Syndicated blog

The distinctions between Optimizely Web Experimentation and Optimizely Feature Experimentation

This blog is part of the series - Unlocking the Power of Experimentation: A Marketer's Insight. Let’s dive into Optimizely's powerful experimentati...

Holly Quilter | Apr 9, 2024

Optimizely SaaS CMS: Balancing TCO and ROI in Your CMS Hosting Decision

With Optimizely SaaS CMS coming soon, I’ve been talking with companies about the tricky business of picking the right core system software for thei...

Johnny Mullaney | Apr 8, 2024 | Syndicated blog

What version of Optimizely CMS am I running?

Optimizely continually rolls out new features for CMS customers and these features are normally for the latest major version of Optimizely CMS (CMS...

David Knipe | Apr 8, 2024 | Syndicated blog