Thursday, 10 October 2013

Webforms MVP and Sitecore 7 POCO/Content Search

Lately I have been doing some work with Sitecore 7 and I had a requirement to work with the webforms rendering engine(as opposed to the MVC rendering engine), while doing this implementation I came across a nice pattern, it turns out Webforms MVP and Sitecore POCO/Content Search play really well together.

Before I get into the details, let me explain what both of these tools are:

  • Webforms MVP is a in implementation of the Model View Presenter pattern that has been floating around the ASP .NET webforms world for a while now. It promotes the separation of rendering and logic concerns in a similar way to MVC. The project website is http://webformsmvp.com/ and there is a bunch more information there.
  • Sitecore POCO/Content Search is the new search API that has come out as part of Sitecore 7. The easiest way of thinking about it, and one if its most useful features, is LINQ to Lucene. This results in a nice strongly typed LINQ/IQueryable syntax for interacting with Lucene indexes, allowing you to bypass the Sitecore databases for a lot of queries, resulting in a faster site.
Now for the bit where these patterns work well together. 

Webforms MVP has been used by a lot of people in Sitecore development for a while, but has traditionally had one major floor in the resulting implementation - a lack of page editor support. With the MVP approach requiring the creation of a "model" class, a lot of developers pass this model up to the rendering layer and render the values using traditional asp .net controls (e.g. asp:literals, asp:hyperlink etc.), as opposed to using Sitecore controls(e.g sc:text, sc:image etc.). While this wasn't explicitly necessary it kind of happened by default, especially if you wanted to use test driven development on your repository/logic layers. 

But, things have changed. Sitecore 7 and its content search API is based around model classes, and facilitates test driven development in a way Sitecore 6 never did.

So if we are now working with model classes how do we use the page editor? Well Sitecore thought of this as they were developing their new API and introduced a class with a particular method: SearchResultItem.GetItem(). This method allows your to retrieve the Item relating to a model as long as it is based on SearchResultItem.

With all of this wired up we have a nice middle ground with somewhat testable code, a nice user experience and a nice separation of concerns.

A sample Model:
    public class SampleModel : SearchResultItem
    {
        public string NonEditableField { get; set; }
    }

A sample presenter with Content Search Query:
    public class SamplePresenter : Presenter<IView<SampleModel>>
    {
        public SamplePresenter(IView<SampleModel> view)
            : base(view)
        {
            this.View.Load += this.Load;
        }
        private void Load(object sender, EventArgs e)
        {
            var item = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_web_index")
                .CreateSearchContext()
                .GetQueryable<SampleModel>()
                .FirstOrDefault(model => model.NonEditableField == "something");
            this.View.Model = item;
        }
    }

A sample view:
<%@ Control Language="C#"
    AutoEventWireup="true"
    CodeBehind="SampleView.ascx.cs"
    Inherits="Layouts.SampleView" %>
<asp:Literal runat="server" ID="nonEditableField"></asp:Literal>
<sc:Text runat="server" ID="editableField"/>

And its sample code behind:
[PresenterBinding(typeof(SamplePresenter))]
    public partial class SampleView : MvpUserControl<SampleModel>
    {
        protected override void OnPreRender(EventArgs e)
        {
            this.nonEditableField.Text = this.Model.NonEditableField;
            this.editableField.Field = "Editable Field";
            this.editableField.Item = this.Model.GetItem();
        }
    }