CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

Plugging UserControl's with StructureMap 2.0

By request, StructureMap 2.0 will finally allow you to use ASP.Net UserControl's for both Dependency Injection and Service Location.  Right now you have to use the programmatic interface to configure the UserControl's.  If there is demand, I'll add an Xml construct specifically for UserControl's.

Ok since this has been going around lately, let's say that you are building a new Model View Controller framework for ASP.Net (yes you could just use MonoRail or Igloo, but let me have my example).  The first thing you build is a FrontController class to handle all incoming requests, then select the requested instance of IPresenter to build the view.  Each IPresenter instance will have to expose an ASCX UserControl for the framework to render the actual html.  The FrontController class and the interface for IPresenter are shown below.

public class FrontController

{

    public void ProcessPage(PageRequest request)

    {

        // 1.) handle the request, and create the Model class

        // 2.) fetch the correct IPresenter

        IPresenter presenter = ObjectFactory.GetNamedInstance<IPresenter>(request.PageName);

        presenter.BuildView(request);

 

        this.writeView(presenter.View);

    }

}

 

public interface IPresenter

{

    object View { get;}

    void BuildView(PageRequest request);

}

In the most basic case I have a simple implementation of IPresenter named PagePresenter that uses and supervises a view represented by an IControl interface.

public interface IControl

{

    void SetName(string name);

}

 

public class PagePresenter : IPresenter

{

    private readonly IControl _control;

 

    public PagePresenter(IControl control)

    {

        _control = control;

    }

 

    public object View

    {

        get { return _control; }

    }

 

    public void BuildView(PageRequest request)

    {

        throw new NotImplementedException();

    }

}

Now, I want to make StructureMap push in the actual implementation of IControl so that I can easily change the view later on, or simply to make the wiring of the dependencies for me.  In the Global.asax file for the application I add the following code:

    void Application_Start(object sender, EventArgs e)

    {

        // Turn off configuration from StructureMap.config

        StructureMapConfiguration.UseDefaultStructureMapConfigFile = false;

 

        // Specify that the default implementation of IControl is TheControl.ascx

        StructureMapConfiguration.BuildInstancesOf<IControl>()

            .TheDefaultIs(

                Registry.LoadUserControlFrom<IControl>("TheControl.ascx"));

 

        // Add the named instance of IPresenter. 

        StructureMapConfiguration.AddInstanceOf<IPresenter>()

            .UsingConcreteType<PagePresenter>()

            .WithName("ThePage");

    }

 

The Fluent Interface is arguably more expressive and readable, but it comes at a cost of increased verbosity.  You might find it cleaner to break up the configuration declarations into separate pieces.  For that very purpose, there is a new class in StructureMap 2.0 called Registry that can be used to make programmatic additions to the StructureMap configuration.  You can either instantiate a Registry directly and pass it into StructureMapConfiguration.AddRegistry(Registry), or more powerfully, write your own like this one.

    public class ControlRegistry : Registry

    {

        // Little helper method

        private void registerView<T>(string url)

        {

            BuildInstancesOf<T>().TheDefaultIs(LoadControlFromUrl<T>(url));

        }

 

        protected override void configure()

        {

            registerView<IControl>("MyControl.ascx");

            // more calls to registerView

        }

    }

Now, we need to direct StructureMap to use our ControlRegistry.  Here's where it gets fun.  StructureMap has always had functionality to scan assemblies for classes or interfaces marked with StructureMap attributes.  As of 2.0 StructureMap is also looking in these assemblies for any public Registry subclasses with a no constructor arguments.  Finally, all we need to do is add the correct assemblies to StructureMap.   

            StructureMapConfiguration.AddRegistry(new ControlRegistry());

 

            // OR

 

            StructureMapConfiguration.ScanAssemblies().IncludeTheCallingAssembly();

 Assuming that the ControlRegistry class is in the assembly that is calling into StructureMapConfiguration, you're all set.  There are other methods on ScanAssemblies() to attach other assemblies.



Comments

inoodle said:

Cheers Jeremy,

Just reading and inwardly digesting :)

# April 4, 2007 8:38 AM

Jeremy D. Miller said:

Feel free to send any feedback in.  It's brand new, so there's no installed base to worry about if I need to change the way it's working.

Jeremy

# April 4, 2007 9:07 AM

Dave Newman said:

Hey Jeremy, this looks pretty good.  I've retrofitted an MVC framework into a legacy app i'm working on, but I haven't gotten an IoC framework in yet to auto-wire dependencies.  Previously i've used Windsor, but I might give structuremap a go.  Sorry. haven't had much of a look into it, but does structure map have any built in nhibernate support? (transactions, opening and closing sessions on page requests)

# April 4, 2007 11:53 PM

Jeremy D. Miller said:

Dave,

What do you have in mind?

I've used StructureMap in the past to help wire up NHibernate (the HttpContext, ThreadLocal, and Hybrid scoping were put in expressly for the way we were using NHibernate last year), but I don't have anything in StructureMap itself for NHibernate.  

I've been uncomfortable trying to put in some sort of generic support for NHibernate lifecycle directly into StructureMap because I've always been worried about coding in a strategy that isn't really generally applicable.

By and large, I've taken the attitude that StructureMap is mostly an IoC tool only, not an application stack.

# April 5, 2007 8:04 AM

inoodle said:

Hi Jeremy,

I'll probably hold off for the moment, as I'm still not sure I should have a dependency on a DI framework! as I mention here: http://intrepidnoodle.com/blog/show/10.aspx

I think the solution might be to use StructureMap but to hide it with an abstraction which uses the programmatic configuration... (which I think you mentioned in a more recent post).

# April 5, 2007 8:40 AM

Jeremy D. Miller said:

Or just steal that tiny bit of code out of StructureMap.  If all you wanted was a way to keep a registry of UserControl's, it wouldn't take much to code.

# April 5, 2007 8:43 AM

inoodle said:

Thanks Jeremy, very kind of you. I'll drop you a line once I've put something together.

# April 5, 2007 10:44 AM

davidt64 said:

Hello,

I've been starting to learn IoC principles by using StructureMap on a little project. I am trying to use the Registry class to perform some StructureMap configuration as outlined in this post. However, the configuration changes made in the configure() routines are somehow not "sticking"; that is, after configure() runs, ObjectFactory.WhatDoIHave doesn't show the changes, and retrieving an instance through ObjectFactory gives a "type not configured" error. I've tried using both ScanAssemblies and AddRegistry. Any idea what else I might try?

Thanks!

# January 12, 2008 10:09 PM

Jeremy D. Miller said:

@davidt64,

Would you send me an email off of the contact up above?  I'll try to help

# January 12, 2008 10:22 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Jeremy D. Miller

Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy previously worked as a systems architect building mission critical supply chain software for a Fortune 100 company and learned agile development practices as a .Net consultant at ThoughtWorks, one of the pioneers of agile development. Jeremy is the author of the open source StructureMap (http://structuremap.sourceforge.net) tool for Dependency Injection with .Net and the forthcoming StoryTeller (http://storyteller.tigris.org) tool for supercharged FIT testing in .Net. Jeremy's thoughts on just about everything software related can be found on his weblog "The Shade Tree Developer" at http://codebetter.com/blogs/jeremy.miller, part of the popular CodeBetter site. Jeremy is a Microsoft MVP for C#. Check out Devlicio.us!

This Blog

Syndication

News

All opinions expressed here constitute my (Jeremy D. Miller's) personal opinion, and do not necessarily represent the opinion of any other organization or person, including (but not limited to) my fellow employees, my employer, its clients or their agents.

About Me

"Best Of" Compendium

StructureMap (Dependency Injection for .Net)

StoryTeller (Supercharged Fit)

Build your own Cab

TestDriven

MVP