A Model View Presenter (MVP) implementation with ASP.NET

Introduction

Currently the Model View Controller (MVC) pattern is widely used for implementing ASP.NET projects, but there are occasions when this cannot be used:

  • It may be that restrictions on the web server means that MVC libraries cannot be installed
  • It may be that an existing project, or team, makes heavy of ASP.NET controls and are not comfortable with the transition to MVC.

An alternative pattern, which provides the same loose coupling as MVC, is the Model View Presenter (MVP). This article describes a simple implementation of this pattern using ASP.NET.

Supporting code for this article is available on github:

https://github.com/RobinHames/ModelViewPresenter.git

The Model View Presenter (MVP) Pattern

A typical MVP structure is shown below:

MVP UML Static Structure

This structure allows the Presenters to interact with views via View Interfaces, which decouples the Presenter from the actual view implementation. This means that the Presenter layer can perform all presentation and navigation tasks without any dependency on the actual UI technology being used (ASP.NET in this example).

This makes code easier to unit test and should also allow code to be ported to a different UI framework more easily.

The Demo Projects

The sample code has a Visual Studio 2013 solution, containing three projects:

  • ModelViewPresenter.Demo.Presenter

This contains all of the Presenters and View interfaces. Typically this layer would be associated with the Model or domain layers, although in this simple demonstration, these lower layers are not implemented.

  • ModelViewPresenter.Demo.Web

This is the top level layer, containing the actual UI. It is an ASP.NET project which references the Presenter project. It is only this layer that has references to System.Web and the associated libraries. This layer also contains a reference to the Castle Windsor IoC container.

  • CacheProvider

This is an implementation of the Loosely Coupled Cache Provider library. See https://rhamesconsulting.com/category/cache-provider/cache-provider-part-1/ for further details on this.

The View Base Interface and the Presenter Base Interface

I find, particularly when using an IoC container such as Castle Windsor, creating base interfaces for other interfaces / classes to implement is a good first step. These base interfaces can allow registration by convention in the IoC container, and can also be useful as generic constraints.

IViewBase.cs

First an empty View Base interface is created:


namespace ModelViewPresenter.Demo.Presenter
{
    ///
    /// Provides a base interface for all view interfaces
    ///
    ///
    /// This will be used to allow IoC container to register all views by convention
    ///
    public interface IViewBase
    {

    }
}

IPresenterBase.cs

Next a Presenter Base interface is created:


namespace ModelViewPresenter.Demo.Presenter
{
    ///
    /// Provides a base interface for all presenters
    ///
    /// The View a Presenter is associated with
    ///
    /// This will be used to allow IoC container to register all presenters by convention
    ///
    public interface IPresenterBase where View : IViewBase
    {
        ///
        /// Initialise the presenter and run any tasks needed on loading the view
        ///
        ///The view object the presenter is working with
        void RunPresenter(View view);
    }
}

All Presenters will be associated with a view interface, therefore the IPresenterBase interface has a generic type that is constrained to be an IViewBase implementation. It also contains a single method that will be used to set up the presenter and run any tasks. It may be that this should really be split into two separate methods to allow the timing of the Run() method to be changed.

Navigation between Views

One area that constantly seems to cause problems in a MVP implementation is how to implement navigation between views. As all logic, include navigation should be decoupled from the web front end, we need a mechanism to navigate at the Presenter level. However, navigation in ASP.NET is carried out by calling Response.Redirect or Server.Transfer. Obviously, the decoupled Presenter layer has no knowledge of these mechanisms.

A simple method (with some restrictions) to handle navigation is to create a new interface, IViewRedirector. Presenters will be able to use this interface to request navigation to another view. They will also be able to pass parameters in the form of a view model to the next view via this interface.

IViewRedirector.cs

The code for the IViewRedirector interface is shown below:


namespace ModelViewPresenter.Demo.Presenter
{
    /// <summary>
    /// Interface to allow navigation to a specified view
    /// </summary>
    public interface IViewRedirector
    {
        /// <summary>
        /// Redirect the user to the specified view, without passing any data
        /// </summary>
        /// <typeparam name="View">The view type to navigate to</typeparam>
        void Redirect<View>() where View : IViewBase;

        /// <summary>
        /// Redirect the user to the specified view
        /// </summary>
        /// <typeparam name="View">The view type to navigate to</typeparam>
        /// <typeparam name="ViewModel">A data model associated with the view being navigated to</typeparam>
        /// <param name="model">A instance of the ViewModel containing data to be passed to the view</param>
        void Redirect<View, ViewModel>(ViewModel model) where View : IViewBase;

        /// <summary>
        /// Retrieve data passed to the view during a redirect
        /// </summary>
        /// <typeparam name="ViewModel">A data model associated with the view</typeparam>
        /// <returns>The data passed to the view</returns>
        ViewModel getData<ViewModel>();

    }
}

This interface provides two methods for redirecting to another view, one with no parameters and one with a ViewModel parameter. The ViewModel parameter method is used to pass data to the next view. The interface also contains a method to retrieve data passed to the view in the form of a ViewModel. There is currently no type checking against ViewModels in this simple interface, so care would be needed to ensure that a call to getData() requests the correct ViewModel type.

PresenterBase abstract class

All Presenters will need to be associated with a View instance, and will also require access to the ViewRedirector. Therefore, common code for to provide this can be abstracted out into a base class, which will implement IPresenterBase and from which all Presenter concrete classes will inherit.

PresenterBase.cs


namespace ModelViewPresenter.Demo.Presenter
{
    /// <summary>
    /// Abstract base class for all Presenters
    /// </summary>
    /// <typeparam name="View">The View a Presenter is associated with</typeparam>
    public abstract class PresenterBase<View> : IPresenterBase<View> where View : IViewBase
    {
        /// <summary>
        /// The view object that the Presenter is working with
        /// </summary>
        protected View presenterView;

        /// <summary>
        /// View Redirector that will allow navigation between views
        /// </summary>
        /// <remarks>
        /// This has public acces to allow the instance to be injected by the IoC container. 
        /// We could use constructor injection but then all concrete presenters would need to implement this constructor
        /// </remarks>
        public IViewRedirector viewRedirector { get; set; }

        /// <summary>
        /// Initialise the presenter and run any tasks needed on loading the view
        /// </summary>
        /// <param name="view">The view object the presenter is working with</param>
        public void RunPresenter(View view)
        {
            presenterView = view;
            RunPresenter();
        }

        /// <summary>
        /// Run any tasks needed on loading the view
        /// </summary>
        /// <remarks>
        /// Concrete implementations of presenters can override this to perform any tasks on the view loading
        /// </remarks>
        protected virtual void RunPresenter()
        {
        }
    }
}

This PresenterBase contains a protected reference to the view object that a Presenter is associated with, this is initialised by the RunPresenter(View) method, which also calls the virtual RunPresenter() method. This RunPresenter() method can be overridden in the concrete Presenter classes to perform any necessary tasks.

The PresenterBase class also contains a IViewRedirector property, which will be injected by the IoC container. I used property injection here, rather than the generally more preferred constructor injection, because constructor injection would require all concrete Presenter classes to implement the same constructor.

Model View Presenter in practice

Now that we have our base interfaces and classes in place, we can look at implementing the sample project. For this simple demonstration, I will create two views, one to allow the user to enter a name, and the second to display this name.

The view interfaces are created in a Views folder in the Presenter project.

IInputView.cs

The IInputView interface will allow the user to enter name and submit it to the server. The code for this interface is:

using System;

namespace ModelViewPresenter.Demo.Presenter.Views
{
    /// <summary>
    /// A view for capturing data from the user
    /// </summary>
    public interface IInputView : IViewBase
    {
        /// <summary>
        /// Get the submitted user data
        /// </summary>
        /// <returns></returns>
        ViewModels.InputViewModel getFormData();

        /// <summary>
        /// Set a callback action to run when the user submits the InputForm
        /// </summary>
        /// <param name="onSubmit"></param>
        void setSubmitAction(Action onSubmit);
    }
}

This view contains two methods. The getFormData() method will be used by the Presenter to retrieve data entered into the view by the user. The setSubmitAction(Action) will provide a callback method from the Presenter, which will be called when the user submits the form.

A ViewModel is associated with the View and used to retrieve data for the Presenter.

InputViewModel.cs

This ViewModel is used to retrieve data from the InputView view.


namespace ModelViewPresenter.Demo.Presenter.ViewModels
{
    /// <summary>
    /// A ViewModel for the InputView
    /// </summary>
    public class InputViewModel
    {
        public string Name { get; set; }
    }
}

IDisplayView.cs

The IDisplayView view interface is used to display data back to the user.

using System;

namespace ModelViewPresenter.Demo.Presenter.Views
{
    /// <summary>
    /// A view for displaying data entered by the user
    /// </summary>
    public interface IDisplayView : IViewBase
    {
        /// <summary>
        /// Pass the form data for display by the view
        /// </summary>
        /// <param name="formData"></param>
        void setFormData(ViewModels.DisplayViewModel formData);

        /// <summary>
        /// Set a callback action to run when the user submits the DisplayView
        /// </summary>
        /// <param name="onSubmit"></param>
        void setSubmitAction(Action onSubmit);
    }
}

This view also contains two methods, setFormData() will allow the Presenter to pass data to the view for display. The setSubmitAction(Action) allows a callback method in the Presenter to be associated with the submit action from the view (this will not actually submit any data, as the view does not have any “get” methods, but it will allow us to navigate back to the input view).

This view also has a ViewModel, which is used to pass data back to the view from the Presenter.

DisplayViewModel.cs

The code for the DisplayViewModel is:


namespace ModelViewPresenter.Demo.Presenter.ViewModels
{
    /// <summary>
    /// A ViewModel for the DisplayView
    /// </summary>
    public class DisplayViewModel
    {
        public string Name { get; set; }

        public static explicit operator DisplayViewModel(InputViewModel inputViewModel)
        {
            return new DisplayViewModel
            {
                Name = inputViewModel.Name
            };
        }
    }
}

This actually has the same properties as the InputViewModel, however it is good practice to give each View its own ViewModel. The DisplayViewModel also has an explicit conversion method to allow an InputViewModel to be cast to a DisplayViewModel. This cast will be used when navigating from the InputView to the DisplayView.

Concrete Presenters

Now we have the View interfaces in place, we can code our concrete Presenter classes. These are contained in the Presenters folder in the Presenter project.

InputPresenter.cs

This presenter is associated with the IInputView interface.


namespace ModelViewPresenter.Demo.Presenter.Presenters
{
    /// <summary>
    /// Presenter to retrieve data from the user, via the InputView
    /// </summary>
    public class InputPresenter : PresenterBase<Views.IInputView>
    {
        protected override void RunPresenter()
        {
            // On load, set action to call when the user submits the data
            this.presenterView.setSubmitAction(this.onSubmit);
        }

        public void onSubmit()
        {
            // Read the input data from the view
            var inputFormData = this.presenterView.getFormData();
            // Redirect to the DisplayView - use explicit conversion to convert InputViewModel into DisplayViewModel
            viewRedirector.Redirect<Views.IDisplayView, ViewModels.DisplayViewModel>((ViewModels.DisplayViewModel)inputFormData);
        }
    }
}

The onSubmit method in the InputPresenter will perform the task of reading the submitted data and navigating to the DisplayView when the user submits the form. The RunPresenter() method is used to set the submit action on the View. The onSubmit() method then calls the getFormData method on the view to read the entered data and then calls the viewRedirect.Redirect() method to navigate to the IDisplayView view. IDisplayView will expect to receive data in a DisplayViewModel object, so the inputFormData is cast to DisplayViewModel in the Redirect call. This cast will use the explicit conversion operator defined in DisplayViewModel.

DisplayPresenter.cs

The DisplayPresenter is associated with the IDisplayView interface.


namespace ModelViewPresenter.Demo.Presenter.Presenters
{
    /// <summary>
    /// Presenter to display the data to the user
    /// </summary>
    public class DisplayPresenter : PresenterBase<Views.IDisplayView>
    {
        protected override void RunPresenter()
        {
            this.presenterView.setSubmitAction(this.onSubmit);
            var data = viewRedirector.getData<ViewModels.DisplayViewModel>();
            this.presenterView.setFormData(data);
        }

        public void onSubmit()
        {
            // Redirect to the InputView (no data passed)
            viewRedirector.Redirect<Views.IInputView>();
        }
    }
}

The DisplayPresenter performs the task of passing data to the view in the RunPresenter() method. It calls viewRedirector.getData() to read the DisplayViewModel object that was passed from the InputPresenter, and calls the setFormData() method on the view. The onSubmit method just navigates back to the InputView, using the overload of viewRedirector.Redirect that does not pass any data.

This completes the Presenter project. We have configured our Presenters and View interfaces to read data, navigate, and display data, but as of yet we have not committed ourselves to ASP.NET.

The ASP.NET Web Project

The ModelViewPresenter.Demo.Web project in the sample code is the root project for the solution, and is the only project that has any references to System.Web and other ASP.NET libraries. In this project we need to provide our view implementations. We also need to provide an implementation for the IViewRedirector interface. We will use Castle Windsor as an IoC container to inject the dependencies.

The ASP.NET web project also has implementations for the various CacheProvider interfaces, which are contained in the WebCacheProviders folder. This article does not cover these implementations, as the CacheProvider is covered by another article. There is also a Windsor installer to register the cache provider classes in the WindsorInstallers folder.

https://rhamesconsulting.com/category/cache-provider/cache-provider-part-1/

ViewRedirector Implementation

The implementation of the IViewRedirector interface is located in the MVP folder in the web project.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using CacheProvider;

namespace ModelViewPresenter.Demo.Web.MVP
{
    public class ViewRedirector : ModelViewPresenter.Demo.Presenter.IViewRedirector
    {
        /// <summary>
        /// Redirect the user to the specified view, without passing any data
        /// </summary>
        /// <typeparam name="View">The view type to navigate to</typeparam>
        public void Redirect<View>() where View : Presenter.IViewBase
        {
            var pathToView = getPathToView(typeof(View));

            if (string.IsNullOrEmpty(pathToView))
                throw new Exception(string.Format("Cannot resolve a URL to view {0}", typeof(View).FullName));

            HttpContext.Current.Response.Redirect(pathToView, true);
            //httpcontext.current.server.transfer(pathToView);
        }
        
        /// <summary>
        /// Redirect the user to the specified view
        /// </summary>
        /// <typeparam name="View">The view type to navigate to</typeparam>
        /// <typeparam name="ViewModel">A data model associated with the view being navigated to</typeparam>
        /// <param name="model">A instance of the ViewModel containing data to be passed to the view</param>
        public void Redirect<View, ViewModel>(ViewModel model) where View : Presenter.IViewBase
        {
            if (!EqualityComparer<ViewModel>.Default.Equals(model, default(ViewModel)))
            {
                HttpContext.Current.Session.Add("ViewRedirectorData", model);
                //httpcontext.current.items.add("viewredirectordata", model);
            }

            // Call the Redirect method
            Redirect<View>();

        }

        /// <summary>
        /// Retrieve data passed to the view during a redirect
        /// </summary>
        /// <typeparam name="ViewModel">A data model associated with the view</typeparam>
        /// <returns>The data passed to the view</returns>
        public ViewModel getData<ViewModel>()
        {
            //object rawData = HttpContext.Current.Items["ViewRedirectorData"];
            object rawData = HttpContext.Current.Session["ViewRedirectorData"];
            if (rawData != null && rawData is ViewModel)
                return (ViewModel)rawData;

            return default(ViewModel);
        }

        #region Cache Of View Paths

        // Use Cache Provider to store the path to a view
        private ICacheProvider<string> _viewPathCache;

        public ViewRedirector(ICacheProvider<string> viewPathCache)
        {
            _viewPathCache = viewPathCache;
        }

        private string getPathToView(Type viewType)
        {
            string viewKey = viewType.FullName;

            // Retrieve the path to the view from the cache, or resolve it from the view instance if not currently chached
            return _viewPathCache.Fetch(viewKey,
                () =>
                {
                    var viewInstance = Global.container.Resolve(viewType);
                    if (viewInstance == null)
                        return string.Empty;

                    return string.Format(@"~\Views\{0}.aspx", viewInstance.GetType().Name);
                },
                null,
                new TimeSpan(24, 0, 0)
                );
        }

        #endregion
    }
}

The ViewRedirector class uses Response.Redirect to navigate to the requested view. Server.Transfer could also be used if required. The decoupled nature of the MVP framework means that if a decision was made to change to Server.Transfer, only the ViewRedirector class would need to be modified. There are not a myriad of Response.Redirect calls to locate and change, as is often the case in traditional ASP.NET applications.

When a request is made to redirect to a view interface, the pathToView helper method is called to resolve the view interface into the relevant URL for the Response.Redirect method. This method uses the CacheProvider to check if a path for the requested view interface has already been resolved and stored in the cache. If it has not, the path is resolved by using the Windsor container to resolve the view interface into a concrete view object. The type name of this object will give the path name, assuming that all views are located in the View folder in the web project. If a different mechanism is required, because, for example, views are located in different folders, only the pathtoView helper method will need to be modified. This again is a benefit of the decoupled design.

The other responsibility for the ViewRedirector class is to handle the transfer of data from the request to the new view. The sample implementation uses the HttpContext Session object to do this. Again, this may be changed if required by just editing the ViewRedirector class (for example if Server.Transfer was used instead of Response.Redirect, the data could be stored in the HttpContext items collection).

PresenterFactory

Whenever a view is displayed, we need to resolve the relevant Presenter for the view, and make sure the RunPresenter() method is called. The easiest method to do this is to call a factory method from the page Load() event for each view implementation.


using ModelViewPresenter.Demo.Presenter;

namespace ModelViewPresenter.Demo.Web.MVP
{
    public static class PresenterFactory
    {
        /// <summary>
        /// Resolve and run the presenter for the specified view interface
        /// </summary>
        /// <typeparam name="View">The view type</typeparam>
        /// <param name="view">The instance of the view</param>
        /// <returns>The presenter instance</returns>
        public static IPresenterBase<View> getPresenter<View>(View view) where View : IViewBase
        {
            var presenter = Global.container.Resolve<IPresenterBase<View>>();

            if (presenter != null)
                presenter.RunPresenter(view);

            return presenter;
        }
    }
}

This factory method uses the Windsor container to resolve the concrete Presenter class for the specified view interface. It also passes the actual view instance to the presenter object when it calls the RunPresenter() method. It would be nice if we could use Castle Windsor to resolve the view object for us (in a similar manner to how Controllers can be resolved in a MVC application), but ASP.NET does not give us any easy hooks into this mechanism (it may be possible to make use of a HttpHandler to resolve the view, but this is out of scope for this simple example).

View Implementations

The view implementations for our two view interfaces (IInputView and IDisplayView) are created as ASP.NET web forms (aspx files). The code behind file is then modified to add the relevant interface to the class to indicate that the aspx page implements the relevant interface.

InputView.aspx

The web form for the InputView contains two server controls, a text box and a button. The button is wired up to the btnSubmit_click method in the code behind class. This method just calls the onSubmit callback method in the Presenter, which is setup during the Presenter initialisation by the setSubmitAction method on the view interface. The getFormData() method on the view interface will then just read the data from the text box control and load this into an instance of the InputViewModel class.

The final important step is to call the PresenterFactory.getPresenter method in the Page_Load event to create and initialise the correct Presenter object.

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using ModelViewPresenter.Demo.Presenter;
using ModelViewPresenter.Demo.Presenter.Views;
using ModelViewPresenter.Demo.Presenter.ViewModels;

namespace ModelViewPresenter.Demo.Web.Views
{
    public partial class InputView : System.Web.UI.Page, IInputView
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // Call this to resolve the correct presenter and run it            
            // N.B. done in the load event so that the web form controls are available to the view interface
            MVP.PresenterFactory.getPresenter<IInputView>(this);
        }

        Action _onSubmit;

        /// <summary>
        /// Set a callback action to run when the user submits the InputForm
        /// </summary>
        /// <param name="onSubmit"></param>
        /// <remarks>
        /// This is the implementation of IInputView.setSubmitAction
        /// </remarks>
        public void setSubmitAction(Action onSubmit)
        {
            _onSubmit = onSubmit;
        }

        /// <summary>
        /// Get the submitted user data
        /// </summary>
        /// <returns></returns>
        /// <remarks>
        /// This is the implementation of IInputView.getFormData
        /// </remarks>
        public InputViewModel getFormData()
        {
            var inputViewData = new InputViewModel();
            inputViewData.Name = txtName.Text;
            return inputViewData;
        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            // Call the onSubmit callback method in the presenter
            if (this._onSubmit != null)
                this._onSubmit();
        }
    }
}

DisplayView.aspx

The web form for the DisplayView contains two server controls, a label and a button. The button is wired up to the btnSubmit_click method in the code behind class. This method just calls the onSubmit callback method in the Presenter, which is setup during the Presenter initialisation by the setSubmitAction method on the view interface. The setFormData() method on the view interface will then just extract data from the instance of DisplayViewModel, which is passed as a parameter to the method, and load this into the label control.

The final important step is to call the PresenterFactory.getPresenter method in the Page_Load event to create and initialise the correct Presenter object.

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

using ModelViewPresenter.Demo.Presenter;
using ModelViewPresenter.Demo.Presenter.Views;
using ModelViewPresenter.Demo.Presenter.ViewModels;

namespace ModelViewPresenter.Demo.Web.Views
{
    public partial class DisplayView : System.Web.UI.Page, IDisplayView
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            // Call this to resolve the correct presenter and run it            
            // N.B. done in the load event so that the web form controls are available to the view interface
            MVP.PresenterFactory.getPresenter<IDisplayView>(this);
        }

        Action _onSubmit;

        /// <summary>
        /// Set a callback action to run when the user submits the DisplayForm
        /// </summary>
        /// <param name="onSubmit"></param>
        /// <remarks>
        /// This is the implementation of IDisplayView.setSubmitAction
        /// </remarks>
        public void setSubmitAction(Action onSubmit)
        {
            _onSubmit = onSubmit;
        }

        /// <summary>
        /// Pass the form data for display by the view
        /// </summary>
        /// <param name="formData"></param>
        /// <remarks>
        /// This is the implementation of IDisplayView.setFormData
        /// </remarks>
        public void setFormData(DisplayViewModel formData)
        {
            if (formData != null)
                lblName.Text = formData.Name;
        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            // Call the onSubmit callback method in the presenter
            if (this._onSubmit != null)
                this._onSubmit();
        }
    }
}

Castle Windsor Initialisation

The final step is to create the Windsor installers for the relevant types and run these installers when the web application starts. The web project has a folder called WindsorInstallers, which contains two installers. The CacheInstaller is used to register the CacheProvider implementations, which are outside the scope of this article. The MvpInstaller registers all of the MVP related classes, which are Presenters, Views and the ViewRedirector implementation.

using Castle.Windsor;
using Castle.MicroKernel.Registration;
using Castle.MicroKernel.SubSystems.Configuration;

namespace ModelViewPresenter.Demo.Web.WindsorInstallers
{
    public class MvpInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            // Register the View implementations by convention (all implementations of IViewBase)
            container.Register(Classes.FromThisAssembly()
                .BasedOn<ModelViewPresenter.Demo.Presenter.IViewBase>()
                .WithService.FromInterface()
                .LifestylePerWebRequest());

            // Register the Presenter implementations by convention (all implementations of IPresenterBase)
            container.Register(Classes.FromAssemblyContaining(typeof(ModelViewPresenter.Demo.Presenter.IPresenterBase<>))
                .BasedOn(typeof(ModelViewPresenter.Demo.Presenter.IPresenterBase<>))
                .WithService.FromInterface()
                .LifestylePerWebRequest());

            // Register the IViewRedirector implementation
            container.Register(
                Component.For<ModelViewPresenter.Demo.Presenter.IViewRedirector>()
                .ImplementedBy<ModelViewPresenter.Demo.Web.MVP.ViewRedirector>()
                .LifestyleSingleton());
        }
    }
}

All the views and presenters are registered with the Windsor container by convention, using the IViewBase and IPresenterBase interfaces. The implementation of the IViewRedirector interface is registered explicitly.

The final step is to modify the Global.asax.cs file to run the Windsor installers on start up.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Optimization;
using System.Web.Routing;
using System.Web.Security;
using ModelViewPresenter.Demo.Web;

using Castle.Windsor.Installer;
using Castle.Windsor;

namespace ModelViewPresenter.Demo.Web
{
    public class Global : HttpApplication
    {
        void Application_Start(object sender, EventArgs e)
        {
            // Code that runs on application startup
            BootstrapContainer();
        }

        public static IWindsorContainer container { get; private set; }

        private static void BootstrapContainer()
        {
            container = new WindsorContainer()
                .Install(FromAssembly.This());
        }
    }
}

The Windsor container is made available as a public static property in Global to allow the PresenterFactory and the ViewRedirector classes to access it and resolve views and presenters.

Leave a comment