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.
Posted
Wed, Apr 4 2007 6:10 AM
by
Jeremy D. Miller