I'm going to present you with a very exciting new feature of StructureMap that is available in the 2.0 release. You can download StructureMap from SourceForge.
There are plenty of articles about StructureMap's service location capabilities, and the documentation is quite good, but I'll throw out the bread-and-butter usage scenario for service location. Here is is.
I have an ICustomerRepository, and an "impl" class that implements the interface, CustomerRepository. As the names suggest, this interface will return an array of Customer(s) given a whole or partial phone number. Here is the full code.
1 using StructureMap;
2
3 [PluginFamily("Default")]
4 public interface ICustomerRepository
5 {
6 Customer[] GetCustomersByPartialPhoneNumber(string phoneNumberOrPartial);
7 }
8
9 [Pluggable("Default")]
10 public class CustomerRepository : ICustomerRepository
11 {
12 public Customer[] GetCustomersByPartialPhoneNumber(string phoneNumberOrPartial)
13 {
14 //do the right thing to find the customers;
15 return null;
16 }
17 }
18
19 public class Customer
20 {
21 private string _name;
22 private string _phoneNumber;
23
24 public Customer(string name, string phoneNumber)
25 {
26 _name = name;
27 _phoneNumber = phoneNumber;
28 }
29
30 public string Name
31 {
32 get { return _name; }
33 set { _name = value; }
34 }
35
36 public string PhoneNumber
37 {
38 get { return _phoneNumber; }
39 set { _phoneNumber = value; }
40 }
41 }
In another place, I want to make use of the ICustomerRepository interface, so all I need are the following lines:
49 //imagine this method were real.
50 ICustomerRepository repository = ObjectFactory.GetInstance<ICustomerRepository>();
51 Customer[] customers = repository.GetCustomersByPartialPhoneNumber("555-5555");
52 return customers;
Of course, when my application starts, I'll put these lines to ensure it will work (or I could use a StructureMap.config file).
47 StructureMapConfiguration.UseDefaultStructureMapConfigFile = false;
48 StructureMapConfiguration.ScanAssemblies().IncludeTheCallingAssembly();
Now that you get the gist of it, I'm going to use StructureMap to enable the Model-View-Presenter pattern in a cleaner way with ASP.NET UserControls. First consider the following usage:
I have a page that has a complicated piece which has been delegated to a usercontrol-presenter pair. The page, of course, will embed this usercontrol in the appropriate place. Immediately you can spot the problem: The "Foo" view is responsible for creating the "Widget" view. Then the Widget view creates its presenter and uses it. This is too much responsibility for both views.
Now consider an alternative:
Now notice that the FooPresenter is responsible for creating and using WidgetPresenter. WidgetPresenter, in return, uses StructureMap to service-locate its view, which implements IWidgetView. Because Widget.ascx.cs implements IWidgetView, this wiring works easily. The StructureMap change that made this possible is the following usage of the configuration. Here is the code:
58 public interface IWidgetView
59 {
60 void ShowWidget(RedWidget theRedWidget);
61 }
62
63 public class RedWidget
64 {
65 }
And the usercontrol that is the view:
5 public partial class Widget : UserControl, IWidgetView
6 {
7 protected void Page_Load(object sender, EventArgs e)
8 {
9 }
10
11 public void ShowWidget(RedWidget theRedWidget)
12 {
13 HttpContext.Current.Response.Write("Red widget shown");
14 }
15 }
And the configuration that makes this possible:
66 void Application_Start(object sender, EventArgs e)
67 {
68 StructureMapConfiguration.UseDefaultStructureMapConfigFile = false;
69 StructureMapConfiguration.ScanAssemblies().IncludeTheCallingAssembly();
70 StructureMapConfiguration.BuildInstancesOf<IWidgetView>().TheDefaultIs(
Registry.LoadUserControlFrom<IWidgetView>("Widget.ascx"));
71 }
Now that we can service-locate asp.net usercontrols, we can inject them as well. The next step is having the WidgetPresenter receive IWidgetView in the constructor. StructureMap will chain-create the usercontrol in order to create WidgetPresenter. Now, our presenter is in control, and the views can concentrate on presenting information to the user and not worry about control flow.