Complete and concrete example of what an ASP.NET WebForms Model-View-Presenter project may look like using StructureMap, NUnit and AutoMoq

For quite some time now I have been thinking of creating some sort of sample project to show how a Model-View-Presenter approach may be used in an ASP.NET WebForms project. Lots of what is out there on this subject seem to be rather fluffy in nature, bits and pieces, not really giving you everything that you need; especially if you have not worked with a MVP paradigm nor Inversion of Control before. I have built a concrete and fully compilable example Visual Studio 2010 solution using StructureMap for IoC, as well as AutoMoq and NUnit for unit testing and automatic mocking. To get your hands on the code, please see the bottom of this post. I realize that the flow in which this is written do not go well with the teachings of Test Driven Development (lucky for me, this post is not about TDD). Being a great fan of the paradigm though, I would recommend you to try it out if you have not done so yet.

Constructing this example solution I have drawn a great deal of inspiration from previously developed code; special thanks to my current, and former, collegues Patrik Akselsson, Karl Ahlin, Oskar Bejbom, Joakim Molin, Jonatan Larsson and Ilja Mikhailov.

MVP solution Visual Studio 2010 solution explorer, overview of the projects.

In order to make things easier to understand, I have divided the solution into four different projects; Generic.Bootstrap, Generic.Core, Generic.Test.Unit and Generic.Web. The Web project, together with Core, are holding the Model-View-Presenter files. Bootstrap is where most StructureMap related things happen, and Test.Unit is the home of NUnit, and AutoMoq. Whether you download the zipped source code archive or get the solution from GitHub, you might need seeing to a few dependencies. All these are listed in the package.config files since I use NuGet, but here they are nonetheless.

The Model-View-Presenter approach

So, why bother with Model-View-Presenter? Why not create your projects using ASP.NET MVC? Well, If you are starting a new project and have the opportunity, then MVC is probably the better choice. If you are stuck with an existing WebForms solution however, it will likely be easier to refactor it into MVP rather than converting your code into a Model-View-Controller project.

If you have the time to implement a MVP solution for your web forms, and your project seems large enough for you to reek the benefits, it is probably worth separating your code and not keep all logic in the code-behind files of your pages and user controls.

MVP solution Visual Studio 2010 solution explorer, Generic.Core.MVP solution Visual Studio 2010 solution explorer, Generic.Web.

There are relatively many files in the Core and Web projects; we will go through them and what they are used for one by one. First, let us look at the PresenterBase class.

PresenterBase.cs

public abstract class PresenterBase
{
    public virtual void Load() {}
    public virtual void PreRender() {}
    public virtual void FirstTimeInit() {}
}

This will be the base of all of our presenters. We will use it to have presenter implementations of the three methods run at the proper time in the life cycle; the Load (5) will be run during OnLoad for instance. It will all be clearer in a while. Next the IView interface.

IView.cs

public interface IView
{
    Uri Uri { get; }
}

This is our base view interface, which all of our other interfaces will be extending. If there are anything that you want available everywhere, this might be the place to put it. Since the example solution does not differ so much in how the PresentedPageBase and the PresentedControlBase are implemented, I have decided only to talk about one of them; the PresentedPageBase.

PresentedPageBase.cs

public abstract class PresentedPageBase<TPresenter> : Page, IView where TPresenter : PresenterBase
{
  private TPresenter _presenter;

  protected override void OnLoad(EventArgs e)
  {
    base.OnLoad(e);
    _presenter = CreatePresenter();

    if (!IsPostBack)
    {
      _presenter.FirstTimeInit();
    }

    _presenter.Load();
  }
  protected TPresenter CreatePresenter()
  {
    return IOC.GetPresenter<TPresenter>(this);
  }

As you can see, the PresentedPageBase class (8) requires a presenter inheriting from the PresenterBase which we just looked at. In the OnLoad event, the generic type presenter is created using Inversion of Control (34); we will come to this in a bit. We then fire the presenter’s implementation of FirstTimeInit if the page is being requested for the first time, i.e. it is not a PostBack event. The presenter’s Load and PreRender implementations are handled in the same way. As the PresentedPageBase implements our IView interface we might want to implement things we have put there; the Uri property in the example code above simply returns the HttpContext.Current.Request.Url.

So, now that we have got some infrastructure done it is time to start looking at how to use it; the start page is our example for this. It uses the Default.aspx and Default.aspx.cs files, as well as the StartPagePresenter class and the IStartPageView interface.

IStartPageView.cs

public interface IStartPageView : IView
{
    string ImportantHeading { get; set; }
    string ImportantText { get; set; }
}

As mentioned before this interface will extend the base IView interface, and then add components of its own; these may be important properties as in the example (5-6), methods, event handlers and so on. Just about anything that you need to stuff in there.

StartPagePresenter.cs

public class StartPagePresenter :  PresenterBase
{
  private readonly IStartPageView _view;
  private readonly IImportantService _importantService;
public override void Load()
{
  _view.ImportantHeading = GetHeading(true);
  _view.ImportantText = GetText(true);
}

public string GetHeading(bool useService)
{
  return useService ?
    _importantService.GetImportantHeading("world") :
    "No heading";
}

Extending the PresenterBase class in our StartPagePresenter (6) will give us the important Load (19) and PreRender methods. While the Dependency Injection will be used through the presenter’s constructor (see the StructureMap section of this post), we set the values of our view’s important properties during the Load event in the page life cycle (21-22). As you can see, the GetHeading method uses another class, ImportantService (28), to retrieve a value; this is done to provide an easy-to-understand unit testing example further on. However, it is important not to let your presenters swell into uncomprehensable monsters. Doing so will leave you with massive pieces of unmaintainable code. As one of my collegues told me at the time that I started working with presenters: “If you need more than say five dependencies, your class is probably doing a lot more than it ought to be.” We will get back to this later.

Now that we have a presenter and a view for our start page, it is time to start looking at what the visitor will actually be seeing. The Default.aspx.cs file is where the interesting line of code is, but first a short code snippet from the code-infront just to show you the controls.

Default.aspx

<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2><asp:Literal ID="litImportantHeading" runat="server"></asp:Literal></h2>
    <p><asp:Literal ID="litImportantText" runat="server"></asp:Literal></p>
    <p><uc:ControlText ID="ucControlText" runat="server" /></p>
</asp:Content>

Default.aspx.cs

public partial class Default : PresentedPageBase<StartPagePresenter>, IStartPageView
{
  public string ImportantHeading
  {
    get { return litImportantHeading.Text; }
    set { litImportantHeading.Text = value; }
  }

There is really not much to talk about here. The code-behind class extends the PresentedPageBase with the StartPagePresenter in place of the generic presenter. This together with the inheritance from the IStartPageView will tie the last Model-View-Presenter knot together. Implementing the ImportantHeading property in the example (10-11), we want the text to show up on the actual page readable by the visitor.

Building the solution and visiting the page now would give us a runtime exception letting us know that the PresentedPageBase _presenter object reference is not set to an instance of an object as it is hit with the first _presenter.FirstTimeInit() call. What is wrong? I thought we were done. Right, IoC using StructureMap.

Inversion of Control using StructureMap

Dependency injection is the glue that ties all this together. I have put what is needed for this functionality in the separate Generic.Bootstrap project as you can see in the image below. Of course there are a lot more things that you can do with StructureMap than what is shown in this example, but this is really all you need for it to wire up your presenters and views.

MVP solution Visual Studio 2010 solution explorer, Generic.Bootstrap.

Let us start by looking at the Initializer class. This is the class that is responsible for setting the whole thing in motion. As you can see in the code snippet, it implements the interface IHttpModule, meaning it will be run at start up. All it really does is creating a new Bootstrapper (10) and having it trigger StructureMap (11). We will get back to the assignment of the IOC.Container property in a moment. One more thing before we move on to the Bootstrapper class; in order for the Initializer module to run, it must first be registered in the system.webServer’s modules section of your web project’s web.config file.

Initializer.cs

public class Initializer : IHttpModule
{
    public void Init(HttpApplication context)
    {
        var bootstrapper = new Bootstrapper();
        bootstrapper.BootstrapStructureMap();
        IOC.Container = bootstrapper.Container;
    }

    public void Dispose()
    {
    }
}

Web.config

<system.webServer>
 <modules>
   <add name="StructureMapInitializer"
        type="Generic.Bootstrap.Initializer, Generic.Bootstrap" />
 </modules>
</system.webServer>

The Bootstrapper class implements StructureMap’s IBootstrapper interface (6) making you implement the BootstrapStructureMap method (10). What this should do is just what the name says it should; bootstrap StructureMap. In this example we use it to scan (17-21) through the assembly that contains the class Bootstrapper (actually this assembly), looking for registries (in other words, classes that extend StructureMap’s Registry class). All of this is baked together and stuffed into a main Container object (8, 12).

Bootstrapper.cs

public class Bootstrapper : IBootstrapper
{
    public IContainer Container;

    public void BootstrapStructureMap()
    {
        Container = new Container(AddRegistryInfo);
    }

    private static void AddRegistryInfo(IRegistry registry)
    {
        registry.Scan(scanner =>
        {
            scanner.AssemblyContainingType<Bootstrapper>();
            scanner.LookForRegistries();
        });
    }
}

So, assuming that everything went well, StructureMap should now have found our CoreRegistry class in the Registries directory. This is a class that can provide methods and configuration for an ObjectFactory or a Container as in our case. The documentation says that extending the Registry class is the recommended way of configuring a StructureMap Container. We use the registry scanner to scan through our code based on four parameters.

CoreRegistry.cs

public class CoreRegistry : Registry
{
  public CoreRegistry()
  {
    Scan(scanner =>
    {
      scanner.RegisterConcreteTypesAgainstTheFirstInterface();
      scanner.AssemblyContainingType<PresenterBase>();
      scanner.WithDefaultConventions();
      scanner.SingleImplementationsOfInterface();
    });
  }
}

This will make the scanner look through the assembly containing the PresenterBase class (in other words the Generic.Core project where we put all of our presenters) using default conventions (13-14). The latter part means that a concrete class named for instance ImportantService that implements an interface named IImportantService automatically will be added to PluginType IImportantService. RegisterConcreteTypesAgainstTheFirstInterface (12) does what it says it does, and the SingleImplementationsOfInterface (15) registers types that are the only implementation of an interface.

IOC.cs

public static IContainer Container;
public static TPresenter GetPresenter<TPresenter>(object view)
{
    var explicitArguments = new ExplicitArguments();
    foreach (var implementedInterface in view.GetType().GetInterfaces())
    {
        explicitArguments.Set(implementedInterface, view);
    }
    return Container.GetInstance<TPresenter>(explicitArguments);
}

One last thing before we can compile the solution and visit the website; we need to retrieve an instance of our presenter. This is done in the IOC class through the GetPresenter method as seen above.

MVP Visual Studio 2010 project, Visiting start page with FireFox.

Unit testing using NUnit and AutoMoq

The last section of this example post mostly circulates around the Generic.Test.Unit project. We will first look at the base classes, and then turn our attention to the StartPagePresenter tests.

MVP solution Visual Studio 2010 solution explorer, Generic.Test.Unit.

Let us begin by looking at the TestBase class; the base on which we will build many of our unit tests. It is used to do a lot of NUnit setup so we can avoid doing it over and over in every test class. The interesting things are the creation of the ClassUnderTest as well as the execution of the Given and When methods.

TestBase.cs

[TestFixture]
public abstract class TestBase<TClassUnderTest> where TClassUnderTest : class
{
  protected abstract TClassUnderTest ResolveClassUnderTest();

  private TClassUnderTest _classUnderTest;
  protected TClassUnderTest ClassUnderTest
  {
    get { return _classUnderTest ?? (_classUnderTest = ResolveClassUnderTest()); }
  }
[SetUp]
public void Init()
{
    _classUnderTest = null;

    Given();
    When();
}

protected virtual void Given()
{
}

As you can see, the ClassUnderTest property (13) calls the protected abstract method ResolveClassUnderTest (8) leaving it to each implementing test class to decide how this setup should be performed. The NUnit attribute SetUp is used to allow for every class under test to have their Given prerequisites as well as their When actions run in a logic order for all the tests extending the TestBase class. It is also possible to add things that should happen after each tests is performed. Since it is a lot of work setting up everything for a test to work, the AutoMockedTestBase class is created to take some of the load off of our shoulders.

AutoMockedTestBase.cs

public abstract class AutoMockedTestBase<TClassUnderTest> : TestBase<TClassUnderTest>
  where TClassUnderTest : class
{
  protected AutoMoqer Container;

  protected override TClassUnderTest ResolveClassUnderTest()
  {
    return Container.Resolve<TClassUnderTest>();
  }
  protected override void Given()
  {
    Container = new AutoMoqer();
    base.Given();
  }
}

AutoMoq is used to automatically setup Moq mocking for our unit tests. Just like the TestBase which it is extending, the AutoMockedTestBase requires the developer to supply a generic class which is supposed to be tested. To avoid having to decide how to create a ClassUnderTest AutoMoq does this for us by resolving it automatically putting it in a mocking container. Basically, Container is set up to hold the class which we are testing, as well as instances of all of its dependencies; in other words, the StartPagePresenterSpecification container would hold instances of both the StartPagePresenter as well as the ImportantService on which it depends.

StartPagePresenterSpecification.cs

public class StartPagePresenterSpecification : AutoMockedTestBase<StartPagePresenter>
{
  protected override void Given()
  {
    base.Given();
    Using<IImportantService>()
      .Setup(s => s.GetImportantHeading("world"))
      .Returns("FakeHeading");

    Using<IImportantService>()
      .Setup(s => s.GetImportantText("WORLD"))
      .Returns("FakeText");
  }

  [Test]
  public void should_return_service_heading_result_when_using_service()
  {
    Assert.AreEqual("FakeHeading", ClassUnderTest.GetHeading(true));
  }

The StartPagePresenterSpecification makes use of the automatic mocking which we just set up (8), and continues with setting up the test prerequisites overriding the Given method. If you have not worked with this kind of testing before, it is rather straight forward; Given contains all of your setup for getting the system in the state you wish it to have at the beginning of your tesets, When performs the actions which will cause your system to respond, and the methods decorated with the Test attribute asserts that your actions on the system had the desired outcome. In the example test above I have omitted the use of When and put the call to the GetHeading method directly into the test method instead.

MVP solution Visual Studio 2010 solution explorer, Running unit tests from the context menu.

Running the unit tests from the right mouse-click context menu will build your projects and then run the selected tests. The Unit Test Sessions window will let you know if a test failed, and why it decided to do so.

MVP solution Visual Studio 2010 solution explorer, Unit Test Session with failing unit test.

Source code

The project is available as a zipped archive and is fully functional, but I would recommend you using the GitHub version as it may contain updates that the zip does not.

Source code: VisualStudioMVPProject_src_1.0.0.0.zip
GitHub link: https://github.com/matkun/Blog/tree/master/ExampleMVPVisualStudio2010Solution

One Response

  1. David "S2" Gustafsson May 4, 2012

Leave a Reply