MVC – Updating multiple partial views from a single (AJAX) action

Sometimes you need to make an AJAX call from your MVC view to perform some server side actions on user changes. You may then want to return some calculated data in a partial view so that you can update the view as presented to the user.

What if you have modified data in more than one partial view?

An application I worked on required some server side calculations that updated both data in a table (one partial view) and summary data displayed in the footer of the page (a second partial view). I would not want to make two separate service side calls to update the two partial views, so I looked into a mechanism to allow me to return the two partial views in the response from the server side call.

I realised that if I could package the two partial view responses into a single object, I could pass this to the client in the response, then use my client side script (JQuery in my case) to unpack the responses and update the two partial views.

The tricky bit was how to package up the partial views. Google pointed to this method to render a Razor view into a string(obtained from ):

public static String RenderRazorViewToString(ControllerContext controllerContext, String viewName, Object model)
{
  controllerContext.Controller.ViewData.Model = model;

  using (var sw = new StringWriter())
  {
    var ViewResult = ViewEngines.Engines.FindPartialView(controllerContext, viewName);
    var ViewContext = new ViewContext(controllerContext, ViewResult.View, controllerContext.Controller.ViewData, controllerContext.Controller.TempData, sw);
    ViewResult.View.Render(ViewContext, sw);
    ViewResult.ViewEngine.ReleaseView(controllerContext, ViewResult.View);
    return sw.GetStringBuilder().ToString();
  }
}

Using this method, I was able to create a controller action that returned a JSON object containing the rendering for my two partial views:

[HttpPost]
public ActionResult _CalculateValues(MyViewModel model)
{
  ModelState.Clear();
  calculationService.CalculateValues(model, User.Identity.Name);
  // The total values and summary values are displayed in two partial views
  // We can't normally return two partial views from an action, but we don't want to have another server
  // call to get the second one, so we render the two partial views into HTML strings and package them into an
  // an anonymous object, which we then serialize into a JSON object for sending to the client
  // the client side script will then load these two partial views into the relevant page elements
  var totalValuesPartialView = RenderRazorViewToString(this.ControllerContext, "_TotalValues", model);
  var summaryValuesPartialView = RenderRazorViewToString(this.ControllerContext, "_SummaryValues", model);
  var json = Json(new { totalValuesPartialView, summaryValuesPartialView });
  return json;
}

Note that my two partial views (“_TotalValues.cshtml” and “_SummaryValues.cshtml”) both use the same model in my example as the view that they are displayed on (MyModelView). I don’t believe this would be a necessary restriction though.

In my view I render the two partial views using mark up similar to:

<div id="_TotalValues" data-url='@Url.Action("_CalculateValues", "Improvement")'>
 @{
   Html.RenderPartial("_TotalValues", Model);
 }
</div>

and

<div id="_SummaryValues">
 @{
   Html.RenderPartial("_SummaryValues", Model);
 }
</div>

Finally, I have a JScript method to make the AJAX call on some event (such as the user changing a value or clicking a button – whatever event the method is bound to) and update the partial views with the response:

// Make an ajax call to recalculate the total values and summary values
function calculateTotalAndSummaryValues() {
  // Get the controlller action url 
  var url = $("#_TotalValues").data('url');
  var data = $("form").serialize();

  // Post the current contents of the form, so we show the Year 1 to 5 benefit values (which might be unsaved)
  $.post(url, data, function (response) {
    // This post will return a JSON object with two properties called totalValuesPartialView and summaryValuesPartialView
    // these will contain the rendering for the two partial views _TotalValues and _SummaryValues
    // by packaging these two up, we can update two partial views from this ajax post
    // with one single server method call
    $("#_TotalValues").html(response.totalValuesPartialView);
    $("#_SummaryValues").html(response.summaryValuesPartialView);
    });
}

This is a very simplistic implementation, with no error handling, just to show the technique.

The key features are:

  • Use a helper method to render a razor partial view into a string
  • Package the partial views into a JSON object
  • Use JScript / JQuery to unpack the AJAX call response and update HTML elements (DIVs) containing the partial views

Use JQuery to automatically update edited data on other parts of a form

If you have a form that has multiple tabs, or other display sections, you might have a need to display data that is entered on one part of the form on other parts. For example the first tab could allow the user to enter a name, this name may then be displayed as read only on other tabs.

There are various methods to do this, but if the read only display is positioned in different parts of the form and in more than one place, you might want to have separate elements for each display.

This little bit of jQuery will allow any changes to the data to be automatically copied to all of the relevant read only display elements.

There are three steps to implement this functionality:

  1. Include the following jQuery in your form (e.g. via a js file)
$(document).ready(function () {
  // On change event for any element with the hasDisplayElement 
  // class
  $(".hasDisplayElement").change(function () {
    updateElementDisplay($(this));
  });

  // Initialise the display element values
  $(".hasDisplayElement").each(function () {
    updateElementDisplay($(this));
  });
});

// Any element with a hasDisplayElement class will check on change
// for other elements with the classes isElementDisplay id, where 
// id is the id of the triggering element (the one with the 
// hasDisplayElement class) if using @HtmlTextFor, etc. the id will 
// be the same as the model property name e.g.
//  @Html.TextAreaFor(model =&gt; model.Description, 
//    new { rows = "8", @class = "form-control asDisplayElement"})
//
// changes will update value in any element like this:
// <textarea class="form-control isDisplayElement Description" 
//    rows="8" disabled="true">@Model.Description</textarea>

function updateElementDisplay(element) {
  var id = element.attr("id");
  var displayElements = $(".isDisplayElement." + id)

  if (element.is("select")) {
    var value = element.children("option:selected").text();
    displayElements.val(value);
  }
  else
    displayElements.val(element.val());
}
  1. Add the “hasDisplayElement” class to all editors that will need to update corresponding display elements elsewhere on the form. Also make sure that all the editor elements have an id.
  2. Add the class “isDisplayElement” followed by the id of the relevant editor element to all of the display elements. By including the id of the editor as a class on the display element, the jQuery script will be able to find the correct display elements whenever a edited value is changed.

Example:

In a MVC project, I needed to displayed the selected Start Date on other parts of the form. The editor for the start date was defined as:

@Html.TextBoxFor(model => model.StartDate, new { @class = "hasDisplayElement" })

MVC will automatically give the text box element an Id of “StartDate”

Elsewhere on the form, where I needed to display the specified start date, I used:

<input type="text" class="isDisplayElement BenefitStartDate" disabled="disabled" />

N.B. The updateElementDisplay method uses the jQuery val() method to update the display elements. Therefore, you need to ensure that any elements that have the “isDisplayElement” class support val() (such as Input elements). If you want to use other elements, such as div, you will need to modify the updateElementDisplay method to detect these and use text() instead.

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.

Adding SQL Cache Dependencies to the Loosely coupled .NET Cache Provider

This post adds SQL Cache Dependency support to the loosely coupled .NET Cache Provider that I described in the previous post (https://rhamesconsulting.com/2012/09/14/loosely-coupled-net-cache-provider-using-dependency-injection/). The sample code is available on github at https://github.com/RobinHames/CacheProvider.git.

Each time we want to apply a cache dependency to a call to fetch or cache a data item we need to supply an instance of the relevant dependency implementation. This suggests an Abstract Factory will be useful to create cache dependencies as needed. We can then use Dependency Injection to inject the factory into the relevant consumer.

Castle Windsor provides a typed factory facility that will be utilised to implement the cache dependency abstract factory (see http://docs.castleproject.org/Windsor.Typed-Factory-Facility-interface-based-factories.ashx).

Cache Dependency Interfaces

First I created a set of cache dependency interfaces in the domain layer, which can be used to pass a cache dependency into the cache provider.

ICacheDependency

The ICacheDependency interface is simply an empty interface that is used as a parent for the specific cache dependency interfaces. This will allow us to place a generic constraint on the Cache Dependency Factory, and will give us a type that can be passed into the relevant Cache Provider methods.

namespace CacheDiSample.Domain.CacheInterfaces
{
    public interface ICacheDependency
    {
    }
}

ISqlCacheDependency.cs

The ISqlCacheDependency interface provides specific SQL caching details, such as a Sql Command or a database connection and table. It is the concrete implementation of this interface that will be created by the factory in passed into the Cache Provider.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CacheDiSample.Domain.CacheInterfaces
{
    public interface ISqlCacheDependency : ICacheDependency
    {
        ISqlCacheDependency Initialise(string databaseConnectionName, string tableName);
        ISqlCacheDependency Initialise(System.Data.SqlClient.SqlCommand sqlCommand);
    }
}

If we want other types of cache dependencies, such as by key or file, interfaces may be created to support these (the sample code includes an IKeyCacheDependency interface).

Modifying ICacheProvider to accept Cache Dependencies

Next I modified the exisitng ICacheProvider<T> interface so that cache dependencies may be passed into a Fetch method call. I did this by adding two overloads to the existing Fetch methods, which take an IEnumerable<ICacheDependency> parameter (the IEnumerable allows more than one cache dependency to be included). I also added a method to create cache dependencies. This means that the implementation of the Cache Provider will require a dependency on the Cache Dependency Factory. It is pretty much down to personal choice as to whether this approach is taken, or whether the Cache Dependency Factory is injected directly into the repository or other consumer of Cache Provider. I think, because the cache dependency cannot be used without the Cache Provider, placing the dependency on the factory into the Cache Provider implementation is cleaner.

ICacheProvider.cs

using System;
using System.Collections.Generic;

namespace CacheDiSample.Domain.CacheInterfaces
{
    public interface ICacheProvider<T>
    {
        T Fetch(string key, Func<T> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry);
        T Fetch(string key, Func<T> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry, IEnumerable<ICacheDependency> cacheDependencies);

        IEnumerable<T> Fetch(string key, Func<IEnumerable<T>> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry);
        IEnumerable<T> Fetch(string key, Func<IEnumerable<T>> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry, IEnumerable<ICacheDependency> cacheDependencies);

        U CreateCacheDependency<U>()
            where U : ICacheDependency;
    }
}

Cache Dependency Factory

Next I created the interface for the Cache Dependency Factory in the domain layer.

ICacheDependencyFactory.cs

namespace CacheDiSample.Domain.CacheInterfaces
{
    public interface ICacheDependencyFactory
    {
        T Create<T>()
            where T : ICacheDependency;

        void Release<T>(T cacheDependency)
            where T : ICacheDependency;
    }
}

I used the ICacheDependency parent interface as a generic constraint on the create and release methods in the factory interface.

Now the interfaces are in place, I moved on to the concrete implementations.

ISqlCacheDependency Concrete Implementation

The concrete implementation of ISqlCacheDependency will need to provide an instance of System.Web.Caching.SqlCacheDependency to the Cache Provider implementation. Unfortunately this class is sealed, so I cannot simply inherit from this. Instead, I created an interface called IAspNetCacheDependency that will provide a Create method to create an instance of the relevant System.Web.Caching Cache Dependency type. This interface is specific to the ASP.NET implementation of the Cache Provider, so it should be defined in the same layer as the concrete implementation of the Cache Provider (the MVC UI layer in the sample code).

IAspNetCacheDependency.cs

using System.Web.Caching;

namespace CacheDiSample.CacheProviders
{
    public interface IAspNetCacheDependency
    {
        CacheDependency CreateAspNetCacheDependency();
    }
}

Next, I created the concrete implementation of the ISqlCacheDependency interface. This class also implements the IAspNetCacheDependency interface. This concrete implementation also is defined in the same layer as the Cache Provider implementation.

AspNetSqlCacheDependency.cs

using System.Web.Caching;
using CacheDiSample.Domain.CacheInterfaces;

namespace CacheDiSample.CacheProviders
{
    public class AspNetSqlCacheDependency : ISqlCacheDependency, IAspNetCacheDependency
    {
        private string databaseConnectionName;

        private string tableName;

        private System.Data.SqlClient.SqlCommand sqlCommand;

        #region ISqlCacheDependency Members

        public ISqlCacheDependency Initialise(string databaseConnectionName, string tableName)
        {
            this.databaseConnectionName = databaseConnectionName;
            this.tableName = tableName;
            return this;
        }

        public ISqlCacheDependency Initialise(System.Data.SqlClient.SqlCommand sqlCommand)
        {
            this.sqlCommand = sqlCommand;
            return this;
        }

        #endregion

        #region IAspNetCacheDependency Members

        public System.Web.Caching.CacheDependency CreateAspNetCacheDependency()
        {
            if (sqlCommand != null)
                return new SqlCacheDependency(sqlCommand);
            else
                return new SqlCacheDependency(databaseConnectionName, tableName);
        }

        #endregion

    }
}

ICacheProvider Concrete Implementation

The ICacheProvider interface is implemented by the CacheProvider class. This implementation is modified to include the changes to the ICacheProvider interface.

First I needed to inject the Cache Dependency Factory into the Cache Provider:

private ICacheDependencyFactory cacheDependencyFactory;

public CacheProvider(ICacheDependencyFactory cacheDependencyFactory)
{
    if (cacheDependencyFactory == null)
        throw new ArgumentNullException("cacheDependencyFactory");

    this.cacheDependencyFactory = cacheDependencyFactory;
}

Next I implemented the CreateCacheDependency method, which simply passes on the create request to the factory:

public U CreateCacheDependency<U>() where U : ICacheDependency
{
    return this.cacheDependencyFactory.Create<U>();
}

The signature of the FetchAndCache helper method was modified to take an additional IEnumerable<ICacheDependency> parameter:

private U FetchAndCache<U>(string key, Func<U> retrieveData, 
    DateTime? absoluteExpiry, TimeSpan? relativeExpiry, IEnumerable<ICacheDependency> cacheDependencies)
and the following code added to create the relevant System.Web.Caching.CacheDependency object for any dependencies and pass them to the HttpContext Cache:
CacheDependency aspNetCacheDependencies = null;

if (cacheDependencies != null)
{
    if (cacheDependencies.Count() == 1)
        // We know that the implementations of ICacheDependency will also implement IAspNetCacheDependency
        // so we can use a cast here and call the CreateAspNetCacheDependency() method
        aspNetCacheDependencies = 
            ((IAspNetCacheDependency)cacheDependencies.ElementAt(0)).CreateAspNetCacheDependency();
    else if (cacheDependencies.Count() > 1)
    {
        AggregateCacheDependency aggregateCacheDependency = new AggregateCacheDependency();
        foreach (ICacheDependency cacheDependency in cacheDependencies)
        {
            // We know that the implementations of ICacheDependency will also implement IAspNetCacheDependency
            // so we can use a cast here and call the CreateAspNetCacheDependency() method
            aggregateCacheDependency.Add(
                ((IAspNetCacheDependency)cacheDependency).CreateAspNetCacheDependency());
        }
        aspNetCacheDependencies = aggregateCacheDependency;
    }
}

HttpContext.Current.Cache.Insert(key, value, aspNetCacheDependencies, absoluteExpiry.Value, relativeExpiry.Value);

The full code listing for the modified CacheProvider class is shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Caching;
using CacheDiSample.Domain.CacheInterfaces;

namespace CacheDiSample.CacheProviders
{
    public class CacheProvider<T> : ICacheProvider<T>
    {
        private ICacheDependencyFactory cacheDependencyFactory;

        public CacheProvider(ICacheDependencyFactory cacheDependencyFactory)
        {
            if (cacheDependencyFactory == null)
                throw new ArgumentNullException("cacheDependencyFactory");

            this.cacheDependencyFactory = cacheDependencyFactory;
        }

        public T Fetch(string key, Func<T> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry)
        {
            return FetchAndCache<T>(key, retrieveData, absoluteExpiry, relativeExpiry, null);
        }

        public T Fetch(string key, Func<T> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry, 
            IEnumerable<ICacheDependency> cacheDependencies)
        {
            return FetchAndCache<T>(key, retrieveData, absoluteExpiry, relativeExpiry, cacheDependencies);
        }

        public IEnumerable<T> Fetch(string key, Func<IEnumerable<T>> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry)
        {
            return FetchAndCache<IEnumerable<T>>(key, retrieveData, absoluteExpiry, relativeExpiry, null);
        }

        public IEnumerable<T> Fetch(string key, Func<IEnumerable<T>> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry, 
            IEnumerable<ICacheDependency> cacheDependencies)
        {
            return FetchAndCache<IEnumerable<T>>(key, retrieveData, absoluteExpiry, relativeExpiry, cacheDependencies);
        }

        public U CreateCacheDependency<U>() where U : ICacheDependency
        {
            return this.cacheDependencyFactory.Create<U>();
        }

        #region Helper Methods

        private U FetchAndCache<U>(string key, Func<U> retrieveData, 
            DateTime? absoluteExpiry, TimeSpan? relativeExpiry, IEnumerable<ICacheDependency> cacheDependencies)
        {
            U value;
            if (!TryGetValue<U>(key, out value))
            {
                value = retrieveData();
                if (!absoluteExpiry.HasValue)
                    absoluteExpiry = Cache.NoAbsoluteExpiration;

                if (!relativeExpiry.HasValue)
                    relativeExpiry = Cache.NoSlidingExpiration;

                CacheDependency aspNetCacheDependencies = null;

                if (cacheDependencies != null)
                {
                    if (cacheDependencies.Count() == 1)
                        // We know that the implementations of ICacheDependency will also implement IAspNetCacheDependency
                        // so we can use a cast here and call the CreateAspNetCacheDependency() method
                        aspNetCacheDependencies = 
                            ((IAspNetCacheDependency)cacheDependencies.ElementAt(0)).CreateAspNetCacheDependency();
                    else if (cacheDependencies.Count() > 1)
                    {
                        AggregateCacheDependency aggregateCacheDependency = new AggregateCacheDependency();
                        foreach (ICacheDependency cacheDependency in cacheDependencies)
                        {
                            // We know that the implementations of ICacheDependency will also implement IAspNetCacheDependency
                            // so we can use a cast here and call the CreateAspNetCacheDependency() method
                            aggregateCacheDependency.Add(
                                ((IAspNetCacheDependency)cacheDependency).CreateAspNetCacheDependency());
                        }
                        aspNetCacheDependencies = aggregateCacheDependency;
                    }
                }

                HttpContext.Current.Cache.Insert(key, value, aspNetCacheDependencies, absoluteExpiry.Value, relativeExpiry.Value);

            }
            return value;
        }

        private bool TryGetValue<U>(string key, out U value)
        {
            object cachedValue = HttpContext.Current.Cache.Get(key);
            if (cachedValue == null)
            {
                value = default(U);
                return false;
            }
            else
            {
                try
                {
                    value = (U)cachedValue;
                    return true;
                }
                catch
                {
                    value = default(U);
                    return false;
                }
            }
        }

        #endregion
    }
}

Wiring up the DI Container

Now the implementations for the Cache Dependency are in place, I wired them up in the existing Windsor CacheInstaller. First I needed to register the implementation of the ISqlCacheDependency interface:

container.Register(
    Component.For<ISqlCacheDependency>()
    .ImplementedBy<AspNetSqlCacheDependency>()
    .LifestyleTransient());

Next I registered the Cache Dependency Factory. Notice that I have not implemented the ICacheDependencyFactory interface. Castle Windsor will do this for me by using the Type Factory Facility. I do need to bring the Castle.Facilities.TypedFacility namespace into scope:

using Castle.Facilities.TypedFactory;

Then I registered the factory:

container.AddFacility<TypedFactoryFacility>();

container.Register(
    Component.For<ICacheDependencyFactory>()
    .AsFactory());

The full code for the CacheInstaller class is:

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

using CacheDiSample.Domain.CacheInterfaces;
using CacheDiSample.CacheProviders;

namespace CacheDiSample.WindsorInstallers
{
    public class CacheInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For(typeof(ICacheProvider<>))
                .ImplementedBy(typeof(CacheProvider<>))
                .LifestyleTransient());

            container.Register(
                Component.For<ISqlCacheDependency>()
                .ImplementedBy<AspNetSqlCacheDependency>()
                .LifestyleTransient());

            container.Register(
                Component.For<IKeyCacheDependency>()
                .ImplementedBy<AspNetKeyCacheDependency>()
                .LifestyleTransient());

            container.AddFacility<TypedFactoryFacility>();

            container.Register(
                Component.For<ICacheDependencyFactory>()
                .AsFactory());
        }
    }
}

Configuring the ASP.NET SQL Cache Dependency

There are a couple of configuration steps required to enable SQL Cache Dependency for the application and database. From the Visual Studio Command Prompt, the following commands should be used to enable the Cache Polling of the relevant database tables:

aspnet_regsql -S <servername> -E -d <databasename> –ed
aspnet_regsql -S <servername> -E -d CacheSample –et –t <tablename>

(The –t option should be repeated for each table that is to be made available for cache dependencies).

Finally the SQL Cache Polling needs to be enabled by adding the following configuration to the <system.web> section of web.config:

    <caching>
        <sqlCacheDependency pollTime="10000" enabled="true">
            <databases>
                <add name="BloggingContext" connectionStringName="BloggingContext"/>
            </databases>
        </sqlCacheDependency>
    </caching>

(obviously the name and connection string name should be altered as required).

Using a SQL Cache Dependency

Now all the coding is complete. To specify a SQL Cache Dependency, I can modify my BlogRepositoryWithCaching decorator class (see the earlier post) as follows:

public IList<Blog> GetAll()
{
    var sqlCacheDependency = cacheProvider.CreateCacheDependency<ISqlCacheDependency>()
        .Initialise("BloggingContext", "Blogs");

    ICacheDependency[] cacheDependencies = new ICacheDependency[] { sqlCacheDependency };

    string key = string.Format("CacheDiSample.DataAccess.GetAll");

    return cacheProvider.Fetch(key, () =>
    {
        return parentBlogRepository.GetAll();
    },
        null, null, cacheDependencies)
    .ToList();
}

This will add a dependency of the “Blogs” table in the database. The data will remain in the cache until the contents of this table change, then the cache item will be invalidated, and the next call to the GetAll() repository method will be routed to the parent repository to refresh the data from the database.

Loosely coupled .NET Cache Provider using Dependency Injection

I have recently been reading the excellent book “Dependency Injection in .NET”, written by Mark Seemann, which I strongly recommend.

Reading the ideas around Dependency Injection made me realise that the Cache Provider code I wrote about earlier (see http://geekswithblogs.net/Rhames/archive/2011/01/10/using-the-asp.net-cache-to-cache-data-in-a-model.aspx) could be refactored to use Dependency Injection, which should produce cleaner code.

The goals are to:

  • Separate the cache provider implementation (using the ASP.NET data cache) from the consumers (loose coupling). This will also mean that the dependency on System.Web for the cache provider does not ripple down into the layers where it is being consumed (such as the domain layer).
  • Provide a decorator pattern to allow a consumer of the cache provider to be implemented separately from the base consumer (i.e. if we have a base repository, we can decorate this with a caching version). Although I used the term repository, in reality the cache consumer could be just about anything.
  • Use constructor injection to provide the Dependency Injection, with a suitable DI container (I use Castle Windsor).

The sample code for this post is available on github, https://github.com/RobinHames/CacheProvider.git

ICacheProvider

In the sample code, the key interface is ICacheProvider, which is in the domain layer.

using System;
using System.Collections.Generic;

namespace CacheDiSample.Domain.CacheInterfaces
{
    public interface ICacheProvider<T>
    {
        T Fetch(string key, Func<T> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry);
        IEnumerable<T> Fetch(string key, Func<IEnumerable<T>> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry);
    }
}

This interface contains two methods to retrieve data from the cache, either as a single instance or as an IEnumerable. the second paramerter is of type Func<T>. This is the method used to retrieve data if nothing is found in the cache.

The ASP.NET implementation of the ICacheProvider interface needs to live in a project that has a reference to system.web, typically this will be the root UI project, or it could be a separate project. The key thing is that the domain or data access layers do not need system.web references adding to them.

In my sample MVC application, the CacheProvider is implemented in the UI project, in a folder called “CacheProviders”:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Caching;
using CacheDiSample.Domain.CacheInterfaces;

namespace CacheDiSample.CacheProviders
{
    public class CacheProvider<T> : ICacheProvider<T>
    {
        public T Fetch(string key, Func<T> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry)
        {
            return FetchAndCache<T>(key, retrieveData, absoluteExpiry, relativeExpiry);
        }

        public IEnumerable<T> Fetch(string key, Func<IEnumerable<T>> retrieveData, DateTime? absoluteExpiry, TimeSpan? relativeExpiry)
        {
            return FetchAndCache<IEnumerable<T>>(key, retrieveData, absoluteExpiry, relativeExpiry);
        }

        #region Helper Methods

        private U FetchAndCache<U>(string key, Func<U> retrieveData, 
            DateTime? absoluteExpiry, TimeSpan? relativeExpiry)
        {
            U value;
            if (!TryGetValue<U>(key, out value))
            {
                value = retrieveData();
                if (!absoluteExpiry.HasValue)
                    absoluteExpiry = Cache.NoAbsoluteExpiration;

                if (!relativeExpiry.HasValue)
                    relativeExpiry = Cache.NoSlidingExpiration;

                HttpContext.Current.Cache.Insert(key, value, null, absoluteExpiry.Value, relativeExpiry.Value);

            }
            return value;
        }

        private bool TryGetValue<U>(string key, out U value)
        {
            object cachedValue = HttpContext.Current.Cache.Get(key);
            if (cachedValue == null)
            {
                value = default(U);
                return false;
            }
            else
            {
                try
                {
                    value = (U)cachedValue;
                    return true;
                }
                catch
                {
                    value = default(U);
                    return false;
                }
            }
        }

        #endregion
    }
}

The FetchAndCache helper method checks if the specified cache key exists, if it does not, the Func<U> retrieveData method is called, and the results are added to the cache.

Using Castle Windsor to register the cache provider

In the MVC UI project (my application root), Castle Windsor is used to register the CacheProvider implementation, using a Windsor Installer:

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

using CacheDiSample.Domain.CacheInterfaces;
using CacheDiSample.CacheProviders;

namespace CacheDiSample.WindsorInstallers
{
    public class CacheInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(
                Component.For(typeof(ICacheProvider<>))
                .ImplementedBy(typeof(CacheProvider<>))
                .LifestyleTransient());
        }
    }
}

Note that the cache provider is registered as a open generic type.

Consuming a Repository

I have an existing couple of repository interfaces defined in my domain layer:

IRepository.cs

using System;
using System.Collections.Generic;

using CacheDiSample.Domain.Model;

namespace CacheDiSample.Domain.Repositories
{
    public interface IRepository<T>
        where T : EntityBase
    {
        T GetById(int id);
        IList<T> GetAll();
    }
}

IBlogRepository.cs

using System;
using CacheDiSample.Domain.Model;

namespace CacheDiSample.Domain.Repositories
{
    public interface IBlogRepository : IRepository<Blog>
    {
        Blog GetByName(string name);
    }
}

These two repositories are implemented in the DataAccess layer, using Entity Framework to retrieve data (this is not important though). One important point is that in the BaseRepository implementation of IRepository, the methods are virtual. This will allow the decorator to override them.

The BlogRepository is registered in a RepositoriesInstaller, again in the MVC UI project.

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

using CacheDiSample.Domain.CacheDecorators;
using CacheDiSample.Domain.Repositories;
using CacheDiSample.DataAccess;

namespace CacheDiSample.WindsorInstallers
{
    public class RepositoriesInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {
            container.Register(Component.For<IBlogRepository>()
                .ImplementedBy<BlogRepository>()
                .LifestyleTransient()
                .DependsOn(new 
                                {
                                    nameOrConnectionString = "BloggingContext"
                                }));
        }
    }
}

Now I can inject a dependency on the IBlogRepository into a consumer, such as a controller in my sample code:

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

using CacheDiSample.Domain.Repositories;
using CacheDiSample.Domain.Model;

namespace CacheDiSample.Controllers
{
    public class HomeController : Controller
    {
        private readonly IBlogRepository blogRepository;

        public HomeController(IBlogRepository blogRepository)
        {
            if (blogRepository == null)
                throw new ArgumentNullException("blogRepository");

            this.blogRepository = blogRepository;
        }

        public ActionResult Index()
        {
            ViewBag.Message = "Welcome to ASP.NET MVC!";

            var blogs = blogRepository.GetAll();

            return View(new Models.HomeModel { Blogs = blogs });
        }

        public ActionResult About()
        {
            return View();
        }
    }
}

Consuming the Cache Provider via a Decorator

I used a Decorator pattern to consume the cache provider, this means my repositories follow the open/closed principle, as they do not require any modifications to implement the caching. It also means that my controllers do not have any knowledge of the caching taking place, as the DI container will simply inject the decorator instead of the root implementation of the repository.

The first step is to implement a BlogRepository decorator, with the caching logic in it. Note that this can reside in the domain layer, as it does not require any knowledge of the data access methods.

BlogRepositoryWithCaching.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using CacheDiSample.Domain.Model;
using CacheDiSample.Domain.CacheInterfaces;
using CacheDiSample.Domain.Repositories;

namespace CacheDiSample.Domain.CacheDecorators
{
    public class BlogRepositoryWithCaching : IBlogRepository
    {
        // The generic cache provider, injected by DI
        private ICacheProvider<Blog> cacheProvider;
        // The decorated blog repository, injected by DI
        private IBlogRepository parentBlogRepository;

        public BlogRepositoryWithCaching(IBlogRepository parentBlogRepository, ICacheProvider<Blog> cacheProvider)
        {
            if (parentBlogRepository == null)
                throw new ArgumentNullException("parentBlogRepository");

            this.parentBlogRepository = parentBlogRepository;

            if (cacheProvider == null)
                throw new ArgumentNullException("cacheProvider");

            this.cacheProvider = cacheProvider;
        }

        public Blog GetByName(string name)
        {
            string key = string.Format("CacheDiSample.DataAccess.GetByName.{0}", name);
            // hard code 5 minute expiry!
            TimeSpan relativeCacheExpiry = new TimeSpan(0, 5, 0);
            return cacheProvider.Fetch(key, () =>
            {
                return parentBlogRepository.GetByName(name);
            },
                null, relativeCacheExpiry);
        }

        public Blog GetById(int id)
        {
            string key = string.Format("CacheDiSample.DataAccess.GetById.{0}", id);

            // hard code 5 minute expiry!
            TimeSpan relativeCacheExpiry = new TimeSpan(0, 5, 0);
            return cacheProvider.Fetch(key, () =>
            {
                return parentBlogRepository.GetById(id);
            },
                null, relativeCacheExpiry);
        }

        public IList<Blog> GetAll()
        {
            string key = string.Format("CacheDiSample.DataAccess.GetAll");

            // hard code 5 minute expiry!
            TimeSpan relativeCacheExpiry = new TimeSpan(0, 5, 0);

            return cacheProvider.Fetch(key, () =>
            {
                return parentBlogRepository.GetAll();
            },
                null, relativeCacheExpiry)
            .ToList();
        }
    }
}

The key things in this caching repository are:

  1. I inject into the repository the ICacheProvider<Blog> implementation, via the constructor. This will make the cache provider functionality available to the repository.
  2. I inject the parent IBlogRepository implementation (which has the actual data access code), via the constructor. This will allow the methods implemented in the parent to be called if nothing is found in the cache.
  3. I override each of the methods implemented in the repository, including those implemented in the generic BaseRepository. Each override of these methods follows the same pattern. It makes a call to the CacheProvider.Fetch method, and passes in the parentBlogRepository implementation of the method as the retrieval method, to be used if nothing is present in the cache.

Configuring the Caching Repository in the DI Container

The final piece of the jigsaw is to tell Castle Windsor to use the BlogRepositoryWithCaching implementation of IBlogRepository, but to inject the actual Data Access implementation into this decorator. This is easily achieved by modifying the RepositoriesInstaller to use Windsor’s implicit decorator wiring:

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

using CacheDiSample.Domain.CacheDecorators;
using CacheDiSample.Domain.Repositories;
using CacheDiSample.DataAccess;

namespace CacheDiSample.WindsorInstallers
{
    public class RepositoriesInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {

            // Use Castle Windsor implicit wiring for the blog repository decorator
            // Register the outermost decorator first
            container.Register(Component.For<IBlogRepository>()
                .ImplementedBy<BlogRepositoryWithCaching>()
                .LifestyleTransient());
            // Next register the IBlogRepository implementation to inject into the outer decorator
            container.Register(Component.For<IBlogRepository>()
                .ImplementedBy<BlogRepository>()
                .LifestyleTransient()
                .DependsOn(new 
                                {
                                    nameOrConnectionString = "BloggingContext"
                                }));
        }
    }
}

This is all that is needed. Now if the consumer of the repository makes a call to the repositories method, it will be routed via the caching mechanism. You can test this by stepping through the code, and seeing that the DataAccess.BlogRepository code is only called if there is no data in the cache, or this has expired.

The next step is to add the SQL Cache Dependency support into this pattern, this will be a future post.