Sitecore Xdb Security/Connectivity Details

What’s xDB Cloud?

As of version 7.5, Sitecore introduced a whole new chapter in its Experience Management Repertoire, which is known as xDB. xDB changed how Sitecore interacts with Customer interactions, and opened up a whole lot of opportunities, and increased scalability exponentially. The key factor in how this was done is the backend of xDB, which is MongoDB. MongoDB is a NoSql database which allows a very high throughput, allowing Sitecore to increase the speed, and scale up data read/write by crazy amounts. For enterprise level sites that get a lot of visitors, this is very good news as Sitecore steps into the world of Big Data.

Given Sitecore is built on top of the Microsoft Technology Stack, there could be some resistance from some companies to jump into a different technological area. Sitecore thought about this, and as of 8.0, they introduced xDB Cloud, a cloud based service for Sitecore to implement xDB, without having to host MongoDB themselves, or go for a cloud solution where they would have to do additional setup for processing and aggregation. This makes it easier to bridge the gap for some customers who were hesitant initially, as they don’t really have to deal with the details of adding on a different type of database to their existing infrastructure and do not need to acquire additional licensing for processing/aggregation/reporting.

This post is not really about xDB Cloud and its features, but if you are interested, there are two very good articles on this.

Firewall Security

Being a cloud service, Sitecore provisions xDB Cloud via a combination of cloud providers (Azure, Mongo Lab, and sometime AWS), so you will need to add a few firewall rules to make this work. For most hosting designs, the CD servers (which interact with Xdb Cloud), are situated in the DMZ, and according to best practices, access (both inbound and outbound) to servers in the DMZ are completely locked down, i.e. nothing is open unless otherwise specified. So one thing you will need to is give your network techs information about what firewall rules to create.

This becomes a little tricky, because xDB Cloud doesn’t connect to one endpoint, and all those endpoints are cloud based, so they are not static. A lot of the documents from Sitecore will say that you need to open outbound connectivity to the azure dynamic Ip range (as stated by http://www.microsoft.com/en-us/download/details.aspx?id=41653). However, any security conscious network department will balk at doing something like that from a DMZ server, so we need to get more specific. Below are the endpoints xDB Cloud needs, and you will need to make a firewall rule for each endpoint:

1. The Discovery service

The discovery service is the endpoint that Sitecore first connects to – to find the information for all the other assets it needs. CM and CD directly connects to the discovery service. This endpoint is located at discovery-xdb-cloud.sitecore.net, and connects on port 443, with HTTPS protocol.

2. Collections Repository

These are the main Mongo DB collections. Every deployment gets a separate set of hosts and ports. These hosts are usually set at the time of deployment and is unique to each deployment. After provisioning a new deployment, you will need to use the REST API Web Service for xDB to find your deployment information.

Some caveats – a collections repository contains three endpoints:

  1. The primary host
  2. The secondary host
  3. The arbiter

Note: protocol here is TCP/IP and TSL/SSL – more on that below.

However, the REST webservice will only tell you about the hosts and their ports, and doesn’t return any information about the arbiter. You will need open a support ticket to get the host and port of the arbiter for your deployment.

3. Reporting Service

The reporting service fetches reporting data from various data sources (for example, the collection or reporting databases) to use in Sitecore reporting applications, such as Experience Analytics. This is also unique per deployment. Also not available from the REST Webservice. You need a support ticket for this as well. This usually connects on port 443, with HTTPS protocol.

4. Search Service

The Search Service provides indexing capability and retrieval of information from the collections. Another endpoint that is unique per deployment, and needs a support ticket. This usually connects on port 443, with HTTPS protocol.

Additional Connectivity for the Collections Repositories

As noted, the connections to the collections repositories uses TCP/IP and TSL/SSL protocol. A client (Mongo Driver) communicates to MongoDB server through TCP/IP connection using SSL encryption. In order to do this, it must install an SSL cert on the local machine (which it does the first time when trying to connect) Whenever any TLS/SSL connection goes out from a windows machine based on the SSL cert installed, it checks the master revocation list location for that certificate, to make sure that certificate is still valid. Since all outbound traffic on the DMZ servers are closed by default, this specific connectivity is blocked.

For SSL-enabled MongoDB deployments, mLab/MongoLab signs all certificates certificate using a root certificate of the DigiCert Global Root CA, and so we need the certificate revocation lists for Digicert.

The URLs of CRL servers are embedded in the certificate (also listed below – but check the certificate on your machine to make sure they are the same):

CRL Distribution Points:
URL = http://crl3.digicert.com/ssca-sha2-g3.crl
URL = http://crl4.digicert.com/ssca-sha2-g3.crl

Authority Information Access
URL = http://ocsp.digicert.com
URL = http://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt

Check the CRLs (Certificate Revocation Lists) and Revoked Certificates section in the following article for port information: https://www.digicert.com/util/utility-test-ocsp-and-crl-access-from-a-server.htm (lest it changes from when this post is published).

Conclusion

xDB Cloud is a very easy way to foray into Experience Analytics as offered by Sitecore, but when getting into network security of DMZ servers, there are a few hurdles to cross. This is not documented as clearly as it should be, so hopefully some of the points here will help you set your networks techs at ease, and smoothly get you all the access you need for Sitecore.

#Protip: Implement permissions to read/write/delete an item of a certain type in Sitecore

I recently had to implement security where users couldn’t delete items, except an item of a certain type. I never had to implement anything like that before, and I was trying all sorts of ways to do this, but the answer is very simple. I’m sure seasoned Sitecore developers know this already, but if you didn’t – configure the permissions in the Security section of the Standard Values of the template. Done.

SV_security

My Year as a Sitecore MVP

Last year, I was fortunate to be awarded my first Sitecore MVP award. The Sitecore MVP Award celebrates the most active Sitecore community members from around the world who provide valuable online and offline expertise that enriches the community experience and makes a difference. As you can guess, it’s a big deal for me.

I wanted to write something about this last year when I first received it, but I wanted to experience a year as an MVP and then write my experiences, hopefully giving an insight into the life of a Sitecore MVP.

Overall Experience

Sitecore treats their MVP’s really well. From early release previews to future roadmaps, MVPs are a very integral part of the Sitecore Product Evolution. There is a constant communication about feature development, enhancements, etc, and MVPs get to pitch in with their feedback to great extents. There are plenty of meetings/seminars and expert panels throughout the year that we can participate in, see new features in beta, etc. In general, the MVPs are part a very big part of the Sitecore Community. As part of the community involvement, I was quoted in the Sitecore White Paper for the initial review of Sitecore 8.1

Sitecore MVP Summit

One of the perks, amongst many others is an annual Sitecore MVP Summit that occurs with all the MVPs and the key personnel from Sitecore. This event is a two to three day event with all sorts of goodness. There is product roadmaps, upcoming features, breakout sessions, plenty of treats. The 2015 MVP Summit was in New Orleans, LA – home of Mardi Gras. We were unfortunately not there at the right time, but we were treated to a night at alligator farm, complete with a band and great food. We spent three days in New Orleans, got to mingle with other MVPs from around the world, got a mountain of information and some cool swag.

On day one, it was mostly meet-n-greet, and I got to meet (in person) all the MVPs I met online. Also got to take in a bit of the French Quarter.

IMG_7380

IMG_7580

IMG_7393

IMG_7415

IMG_7409

IMG_7429

IMG_7434

IMG_7580

On day two, the sessions took up most of the day and in the evening we went to the alligator farm, and went on a safari tour of the bayou.

IMG_7495

IMG_7491

IMG_7462

Day three was also full of sessions, and that was just the beginning, as we segwayed into the SUGCON US.

IMG_7396

IMG_7540

Onwards..

I was recently awarded the Sitecore MVP award 2016, for the second time. I am honored and grateful that I am fortunate enough to be a part of this esteemed group and that I get to interact with this group day in day out. Looking forward to another year of awesome activities and even more knowledge!

A Richer Experience Editor Editing Experience: Part 2

This is the second part of a two part series post, where we look into maximizing the experience of a content editor, by providing them with on screen help and guidance. This is a remake of an older approach that I originally wrote about (using webforms). The idea is the same, but the approach is a little different. The end result for both are the same – you can see more about the goal of the endeavor in the original posts:

For Sitecore MVC, we changed it around a little bit to add some more flexibility, and update for MVC:

Where we left off…

We left off where we created all the views – so, we created our main view (the one we hook up to the View Rendering in Sitecore). We then created the Display View, and the Edit View. We also created the items based on the Help Template.

template5

 

template2

 

CustomView.cs

Now, we will then create a Base class that all views will inherit from, called CustomView.cs. We will use this view to centralize the logic:


public abstract class CustomView<T> : WebViewPage<T>
    {
        
	private string _viewName;
        private string _viewFolder;

	public MvcHtmlString ShowModalView(string displayViewName, string editViewPath, string displayViewPath, object theModel, bool useSeparateViews, string helpViewName = null)
        {
            return ShowModalView("PageEditHelp", "Common", "ShowHelp", displayViewName, editViewPath, displayViewPath, theModel, useSeparateViews, helpViewName);
        }

       
	public MvcHtmlString ShowModalView(string controller, string area, string action, string displayViewName, string editViewPath, string displayViewPath, object theModel, bool useSeparateViews, string helpViewName = null)
        {
            //if Sitecore is in page editing mode, then execute the pageedit controller action and return the result to the screen
            //this will check what help needs to be displayed, and then return the appropriate help view
            if (IsInPageEditingMode)
            {
		return Html.Action(action, controller, new { Area = area, model = theModel, viewname = displayViewName, editViewPath = editViewPath, useSeparateViews = useSeparateViews, ViewFolder = ViewFolder, helpViewName = helpViewName });
        
            }
            //if Sitecore is NOT in page editing mode, and the item has a datasource, then show the regular display view - we are probably in just a regular preview mode.
            else if (HasDataSource)
            {
                return Html.Partial(displayViewPath, theModel);
            }
            //if Sitecore is not in page editing more, and there is no datasource, return empty string - there is nothing to display (also in preview mode)
            else
            {
                return new MvcHtmlString("");
            }
        }

     
        private void GetViewProperties()
        {
            /*
                If the view being used is: /Areas/Common/Views/Media/RichText.cshtml
                 - this.VirtualPath would be: /Areas/Common/Views/Media/RichText.cshtml
                 - viewFileName would be: RichText.cshtml
                 - _viewName would be: RichText
                 - _viewFolder would be: /Areas/Common/Views/Media/
            */

            string[] segments = this.VirtualPath.Split('/');
            string viewFilename = segments.Last<string>();

            _viewName = viewFilename.Split('.').First<string>();
            _viewFolder = this.VirtualPath.Replace(viewFilename, "");
        }

        public string ViewName
        {
            get
            {
                if (String.IsNullOrEmpty(_viewName))
                {
                    GetViewProperties();
                }

                return _viewName;
            }
        }

        public string ViewFolder
        {
            get
            {
                if (String.IsNullOrEmpty(_viewFolder))
                {
                    GetViewProperties();
                }

                return _viewFolder;
            }
        }

        public string DisplayViewPath
        {
            get
            {
                return (ViewFolder + ViewName + "Display.cshtml");
                
            }
        }

        public string EditViewPath
        {
            get
            {
                return (ViewFolder + ViewName + "Edit.cshtml");
            }
        }

        public string GenericPageEditHelp
        {
            get
            {
               return ("GenericPageEditHelp");
            }    
        }

    }

To make sure your views inherit from this class, you need to set the base inherit class in the web.config inside the Views folder:


<system.web.webPages.razor>
		<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
		<pages pageBaseType="MyNamespace.CustomView">
      <namespaces>
	<add namespace="Sitecore.Mvc" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
      </namespaces>
    </pages>
</system.web.webPages.razor>


What’s going on in CustomView.cs?

The Properties

In the base class for the Views, we implemented a few properties – these properties derive from the existing View – e.g. if the View file is HoverTitlePanel.cshtml:

  • DisplayViewPath: the value of this property will be /Areas/[folder structure]/]HoverTitlePanelDisplay.cshtml
  • EditViewPath: the value of this property will be /Areas/[folder structure]/]/HoverTitlePanelEdit.cshtml
  • ViewName: the value of this property will be HoverTitlePanel
  • ViewFolder: the value of this property will be whatever folder this View is placed in
  • GenericPageEditHelp: this is just a static string property to designate a Help View that will be used by default, if no specific View is set for the Help View

We also implemented a method, called ShowModal. The main purpose of this method is to decide what view to show. If you remember, we created three different views, and we call this method in the main View – the one that is connected to the Sitecore View Rendering (see below).

The ShowModal Method

The ShowModal method is responsible for deciding whether to call the controller to show the help instructions, or just display the view. For each rendering/module .cshtml file, instead of showing the data from the Model, we call this method:


@model Hover_Title_Panel
@{
    Layout = null;
}

@ShowModalView(ViewName, EditViewPath, DisplayViewPath, Model, false, GenericPageEditHelp)

The parameters for the method are based on the properties as part of CustomView – the other parameters are:

  • UseSeparateViews: a boolean value to designate whether to use separate views for the help views i.e. one for No-Datasource, one for RegularEdit. This is completely optional, as stated earlier. Pass in false to use a single view.
  • HelpViewName: this specifies a specific view name to use for the help views. If this is not passed in, it uses the GenericPageEditHelp view, which can be passed in explicitly (or not, because it takes a default null value)

 

PageEditHelp Controller

We have a PageEditHelp controller, which has the logic of what help view to show:


public class PageEditHelpController : CustomController
 {
 //
 // GET: /Common/PageHelp/
 public ActionResult Index()
 {
 return View();
 }

 public PageEditHelpController(ISiteService siteService) : base(siteService)
 {

 }

 public ActionResult ShowHelp(BaseModel model, string viewname, string editViewPath, bool useSeparateViews, string viewFolder, string helpViewName = null)
 {
 //do editing logic here
 //if there is no data source, then display no datasource help and pass the "[viewname]-nodatasource.cshtml"
 //if there IS a datasource, but it needs items, then display the "[viewname]-nodataitems.cshtml"
 //if there are data item, then just show the basic editor instructions "[viewname]-editinstructions.cshtml"

 //instantiate new RenderingHelp Model
 RenderingHelp rh = new RenderingHelp();

 //set the RenderingHelp Model property to the actual model (the one needed for the view)
 rh.Model = model;

 //set boolean to see if it has a datasource or not (will be used to decide whether to show the regular edit or display rendering)
 rh.HasDataSource = RenderingContext.Current.Rendering.DataSource.IsGuid();

 //Get help item
 Page_Editor_Help helpItem = GetHelpItem<Page_Editor_Help>(viewname, viewFolder);

 //if no help item was found, fail with showing just the edit view path 
 // todo: if helpItem is not found and there is no datasource. then return a return helpitem
 // todo: if helpItem is not found and there is a datasource, them return the editviewPath

 if (helpItem == null &amp;amp;&amp;amp; !rh.HasDataSource)
 {
 return View(editViewPath, model);
 }
 else
 {
 //no help item found. Set a default empty help item
 helpItem = Sitecore.Context.Database.GetItem(SiteSettings.GlobalPageEditDefaultHelpPath);

 //set the help text based on what step the view is in.
 //use GetHelpContent() method to get the item that holds the help content, and get the field that we need
 rh.HelpText = GetHelpContent(helpItem, false, ref viewname, useSeparateViews);

 

 //pass the edit view path (id HasDataSource is 'true', then show the edit rendering)
 //Note: if the creator of the view decides that they won't need a separate view for editing, then they will just pass the display view path for the editviewpath
 ViewBag.EditViewPath = editViewPath;

 if (!String.IsNullOrWhiteSpace(helpViewName))
 {
 return View(helpViewName, rh);
 }
 else
 {
 return View(viewname, rh);
 }
 }
 }

 private Tmodel GetHelpItem<Tmodel>(string viewname, string viewFolder) where Tmodel : BaseModel, new()
 {
 try
 {
 Item item = Sitecore.Context.Database.GetItem(GenericHelper.EnsureSlashesAtEnd(SiteSettings.GlobalPageEditHelpPath) + viewname);

 //didn't find item in the root directory, so look in first level folder
 if (item == null)
 {
 //if we have a view folder, then try to look at least one level up
 if (!String.IsNullOrEmpty(viewFolder))
 {
 //remove beginning and trailing slashes
 viewFolder = viewFolder.Trim('/');

 //find the first level folder, and look up the item there
 string[] folders = viewFolder.Split('/');
 string folder = folders.Last<string>();

 item = Sitecore.Context.Database.GetItem(GenericHelper.EnsureSlashesAtEnd(SiteSettings.GlobalPageEditHelpPath) + folder + "/" + viewname);
 }
 //if STILL not found, then return null
 if (item == null)
 {
 //TODO: log that help item was not found
 return null;
 }
 }

 Tmodel obj = new Tmodel();
 obj.SetModel(item);

 return obj;
 }
 catch
 {
 //TODO: log that help item was not found
 return null;
 }
 }

 
 public string GetHelpContent(Page_Editor_Help helpItem, bool needDataitems, ref string viewname, bool useSeparateViews)
 {
 

 /*
 
 if there is no datasource, then display the no-datasource field - so that they can add in the datasource
 if there IS a datasource, but this rendering needs data (such as other items), then show no-dataitems field - so that they can add in the items needed (add one by one)
 if both the datasource and at least one data item is there, show the regular page editor instructions, so they can edit the content.
 
 This also using a separate view for when there is no datasource, vs when there is no dataitems, vs when there is a regular edit.
 However, it is possible that not all views are going to be complicated enough that there will be a need to show three separate views - 
 * Chances are most of the views will be simple single datasource item views. 
 * So added a boolean parameter to see if the different datalogic needs to be performed to show the appropriate view.
 * If the parameter is set to 'true', then we perform the logic to set the viewname to the appropriate view.
 * If the parameter is set to 'false', then we just use the viewname as it is, and the same view should exist within the 'PageEditHelp' view folder
 
 If you need to have separate views, name them accodingly:
 * If the name of the view is "HoverTitlePanel", the corresponding viewnames should be:
 * HoverTitlePanel-NoDatasource
 * HoverTitlePanel-NoDataItems
 * HoverTitlePanel-RegularEdit
 
 * When not using separate view, it will just be HoverTitlePanel
 */


 if (!RenderingContext.Current.Rendering.DataSource.IsGuid())
 {
 if (useSeparateViews)
 {
 viewname = viewname + SiteSettings.ViewSuffixForNoDatasource;
 }

 return helpItem.No_DataSource_Help.Raw;
 }
 else if (RenderingContext.Current.Rendering.DataSource.IsGuid() &amp;amp;&amp;amp; needDataitems)
 {
 if (useSeparateViews)
 {
 viewname = viewname + SiteSettings.ViewSuffixForNoDataItems;
 }
 return helpItem.No_Data_Help.Raw;
 }
 else
 {
 if (useSeparateViews)
 {
 viewname = viewname + SiteSettings.ViewSuffixForRegularEdit;
 }
 return helpItem.Page_Editor_Instructions.Raw;
 }
 
 }
 }

How it connects together

Now that we have all the views, and the PageEditHelpController, and CustomView.cs base class for all the views, we can step through what happens:

1. In the View Rendering view, call the ShowModal Method

Majority of the parameters are available in the base class, and doesn’t need to be passed in, but we are passing it explicitly for the purpose of this example. Note that we can pass in the DisplayViewPath for the editing view path parameter as well, if we have a simple view that doesn’t require a different structural layout.

2. ShowModal Executes

When the ShowModal method is called, it checks to see if Sitecore is in Page Editing mode. If this is true, it executes the PageEditHelp controller’s ShowHelp action. If it is not in Page Editing mode, and the rendering/module has a datasource set, then just show the regular display view. If a datasource is not set, return empty string, so the rendering/module doesn’t error out.

3. PageEditHelp/ShowHelp Executes

This method first initializes the model for the help views and then it tries to get the help item, based on the ViewName parameter. If it finds the item, it then sets the appropriate values for the Model for the rendering help views. If it doesn’t find a help item, but a datasource has been set, it returns the editing view. If it doesn’t find a help item, it sets default help item before returning the help view.

The help views are very simple:


@model RenderingHelp
@{
    Layout = null;
}


<div class="pagehelp">
    @Html.Raw(Model.HelpText)
</div>


@{ var newModel = ConvertModel<Hover_Title_Panel>(@Model.Model);}

@if (Model.HasDataSource)
{
    @* For simple views, the edit panel is empty, and we are using the display view*@
    @* For complicated views, switch this to use the edit view.*@
    @Html.Partial((string)ViewBag.EditViewPath, newModel)
}

As mentioned, you don’t have to make a specific help view for each View Rendering view. There is a generic help view that can be used for all renderings. Don’t pass in any parameter for HelpViewName in ShowModal. The generic page edit help view looks like this:


@using System.Reflection

@model RenderingHelp
@{
	Layout = null;
}


@if (Model.HelpText.Trim().Length > 0)
{

<div class="pagehelp">@Html.Raw(Model.HelpText)</div>

}

@{
	MethodInfo convertModelMethod = typeof(RenderingHelp).GetMethod("GetActualModel");
	MethodInfo generic = convertModelMethod.MakeGenericMethod(Model.Model.GetType());
	var newModel = generic.Invoke(Model, null);
}

@if (Model.HasDataSource)
{
	@* For simple views, the edit panel is empty, and we are using the display view*@
	@* For complicated views, switch this to use the edit view.*@

	@Html.Partial((string)ViewBag.EditViewPath, newModel)
}

Conclusion

This may seem complicated, but once the foundation is done, the only work needed to maintain this is to make two views per View Rendering. You can have as little or as much control over the views:

  • Required: You have just the two views per View Rendering
  • Optional: You can have three views per rendering (if you want to have a separate view for editing)
  • Optional: You can have a specific help view for help for each View Rendering
  • Optional: You can have a specific help view for each step in the editing process (no datasource, no data, and regular edit)

All of the views are created based on naming convention (like asp.net MVC) and so there is really no coding involved, unless you want to get granular in your display.

We have had really good feedback from our users with this approach, as even a novice can walk through a content editing process without a lot of training. Eventually I would like to improve this to hook into a pipeline that adds the ‘Display’ and ‘Edit’ suffix automatically and have this at a more foundational level. I would also like to make sure this works for controller renderings. Would definitely love some input – maybe all this can be done in a much smoother way, so fire away!

A Richer Experience Editor Editing Experience: Part 1

Using Sitecore XP CMS features to it’s Fullest Capability

One of the best features of Sitecore XP is the Experience Editor (formerly known as Page Editor). In order to utilize this feature fully and make it as user-friendly as it can be, I had written about an approach that makes the life of a content editor easy, by providing on screen guidance for editing content and editing components. You can read about it in the two part post here:

It was written with webforms in mind. We have since updated it to use on MVC projects, but on a new MVC project, we decided to try a different approach behind the scenes – one that involves more centralization, and more flexibility.

The results are the same as the old approach – the output of what this achieves is outlined in Part 1 of the Post: Easier Page Editor Adoption for Content Editors – How it works for the Content Editors. It would be a nice refresher to see what this achieves and then come back here to understand what we need to do for it to work in MVC.

Just like the other approach, I’ve decided to break this down into two parts (and because one post became too big):

The Basic Idea

In Sitecore MVC (as in webforms), the basic idea is very simple – whenever we add a new rendering/module to a placeholder – or when a rendering/module has been placed via standard values – we want to show some help instructions so that the content editor knows what to do next. In webforms, we were able to utilize user controls. Inside a MVC view, we are not really aware of the page state, so we have to centralize it somehow. When a View Rendering loads, with the Model being passed in, we must display the right instructions (or not – because we are not in page editing mode).

We’ve decided to add a some more flexibility to this concept – one of being that for Page Editor, sometimes it makes sense to have a completely different view of a page, than what the final display looks like. This is not a new concept (as Nick Wesselman wrote about it way back), and it makes content editing renderings/modules such as Image Carousels, and Video Slideshows much easier, by breaking them down and displaying all the different elements of the modules (which are usually hidden).

So, architecturally, the solution should provide:

  1. The ability to have editing help instructions per View (rendering/module)
  2. The ability to have a different display HTML vs editing HTML
  3. The ability to define the business logic for how each module shows its’ help instructions
  4. The ability to use a generic version of both #1, #2 and #3, and not have to make an individual view for every step.

The Setup

To follow the approach here, we need the following:

  1. The view for Sitecore rendering (duh)
  2. A view for displaying the content in preview or live mode
  3. A view for laying out the content in a different format for ease in editing
  4. A view to layout the instructions corresponding to that rendering/module
  5. Templates to hold the help instructions data
  6. Items based on template in #5 for each rendering/module.

Note: as mentioned in what the approach should provide, #3 and #4 are optional, and there should be a generic view for both, that outputs the help instructions and editing view in a generic format. This approach shouldn’t add more work than necessary.

The Views

When we create views in our VS solution, the folder structure tends to get created based on controllers, or for simple view renderings, we can create our own folder structure:

template3

To create the renderings, we point them to .cshtml file – standard operating procedure.

template4

We then would need to create different views, for editing, and displaying – we decided to just suffix them using “Display.cshtml” and “Edit.cshtml”:

template5

The views name “…Display.cshtml” would show in preview mode, and “…Edit.cshtml” would show in Page Edit Mode.

Page Edit Help Controller

We need to have a PageEditHelp controller, which has the business logic to show the instructions:

template6

… and the corresponding views folder, to have a corresponding help view for each rendering/module.

template7

An Example

A simple example: to create a View Rendering for a Title Panel (an image with some text and headline that hovers when you mouseover it), these are all the views you will need, depending on how granular you want to control the display:

Tradtional Sitecore Development: HoverTitlePanel.cshtml – you are essentially done, as long as you used Field Renderers, you should be good.

To create a guided help View Rendering, you will need:

  • HoverTitlePanel.cshtml – the standard view
  • HoverTitlePanelDisplay.cshtml – the display/preview view
  • HoverTitlePanelEdit.cshtml – this view will display when Sitecore is in Page Editing mode
  • HoverTitlePanel.cshtml – in the PageEditHelp Views folder – this is needed only if the help instructions are complicated enough that a completely different HTML structure is necessary
  • HoverTitlePanel-NoDataSource.cshtml, HoverTitlePanel-RegularEdit.cshtml and HoverTitlePanel-NoData.cshtml – these views are necessary only if the help instructions for each step of the module content creation is drastically different. This is a very rare scenario.

So, to summarize, you can customize the help instruction at a very granular level – or not – to just display simple help instruction on top of the page, all you need is the HoverTitlePanel.cshtml and HoverTitlePanelDisplay.cshtml – of this, you only really need to worry about HoverTitlePanelDisplay.cshtml to render your model data. (HoverTitlePanel.cshtml will call a simple method, and nothing else – which we will show in Part 2 of this post)

The Assets

We still need the same assets that we had in the earlier approach:

  • Templates to hold the instructions data
  • A mechanism to decide whether to show the help or the regular display view

The Templates and Items Setup

There are three main steps where we need to show instructions. They are:

  1. When a rendering/module is placed on a page without a datasource via standard values.
  2. Once the item is created, instruct how to add associated content (i.e. setting the datasource)
  3. Once the associated content is set, how to enter rendering/module specific content.

The templates don’t really change from before:

template0

template1

Notice the the three different fields correspond to the three steps where we need to show the content:

  • Field No DataSource Help is for step #1
  • Field No Data Help is for step #2
  • Field Page Editor Instructions is for step #3

We would need to create a Help item for each rendering/module, to hold the help instruction – in multiple languages, if so desired.

template2

We then need to create a base class for the Views, and the PageEditHelp controller. Once those are created, the only thing needed from a perspective for rendering development are the different views. As mentioned, they could be two views, or more, depending on how granular you want to get.

The second part of this post explains how to connect all these views and make it work with the PageEditHelp Controller.

Changes to Dependency Injection in Sitecore 8.1

If you are reading this, chances are you have used some form of DI in your Sitecore Solution. If you’ve used some of the standard IoC containers in an MVC application, you’ve also most likely used a custom dependency resolver. Using Simpleinjector, you can make a pretty simple custom dependency resolver for Sitecore – see here. In pre Sitecore 8.1, you would also need to make a custom controller factory, so that you can resolve using your own container. There are number of posts that shows you how to build a cool custom controller factory:

What’s new in Sitecore 8.1?

Pre Sitecore 8.1, you had to make a custom controller factory because Sitecore by default did not use the DependencyResolver to create a controller instance. It was something like this:

 if (TypeHelper.LooksLikeTypeName(controllerName))
      {
        Type type = TypeHelper.GetType(controllerName);
        if (type != (Type) null)
          return TypeHelper.CreateObject(type);
      }
      return this.InnerFactory.CreateController(requestContext, controllerName);

In Sitecore 8.1, it uses the current DependencyResolver (as set by your application in App_Start) to create the controller instance – if it fails (i.e. didn’t find the concrete type in your container), then it still uses TypeHelper (Sitecore.Mvc.Helpers) to create the instance.

  if (TypeHelper.LooksLikeTypeName(controllerName))
      {
        Type type = TypeHelper.GetType(controllerName);
        if (type != (Type) null)
        {
          IController controller = DependencyResolver.Current.GetService(type) as IController ?? TypeHelper.CreateObject<IController>(type);
          if (controller != null)
            return controller;
        }
      }
   return this.InnerFactory.CreateController(requestContext, controllerName);

What this really means is that you don’t have to use your own custom controller factory anymore. You still need to use the fully qualified class name for the controller, though.

An update to how setup a custom dependency resolver

In my earlier post, I wrote about a simple custom dependency resolver using SimpleInjector. Steven van Deursen, one of the founders of SimpleInjector showed me a better way to do this, so that it would be compatible with upcoming changes in v3 and future changes. It involves wrapping your own implementation with a wrapper, so that creation of all instances are delegated to the SimpleInjectorDependencyResolver. Instead of implementing the GetService method yourself, you use the wrapper’s GetService method – this way, any updates done to SimpleInjector is seamless. So now, the class would look like this:

public class CustomDependencyResolver : IDependencyResolver
    {

        private IDependencyResolver wrappedResolver;

        public SitecoreDependencyResolver(IDependencyResolver wrappedResolver)
        {
            this.wrappedResolver = wrappedResolver;
        }



        public object GetService(Type serviceType)
        {
            try
            {
                return this.wrappedResolver.GetService(serviceType);
            }
            catch
            {
                return Sitecore.Mvc.Helpers.TypeHelper.CreateObject<IController>(serviceType, new object[0]);
            }

        }



        public IEnumerable<object> GetServices(Type serviceType)
        {
            return this.wrappedResolver.GetServices(serviceType);
        }

    }

And then when setting the DependencyResolver in App_Start, it would look like this:

public static class SimpleInjectorInitializer
    {
        

        //Initialize the container and register it as MVC Dependency Resolver.
        public static void Initialize()
        {
            var container = new Container();
            
            InitializeContainer(container);

            container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
            
            container.Verify();

            DependencyResolver.SetResolver(new CustomDependencyResolver(new SimpleInjectorDependencyResolver(container)));

        }
     
        private static void InitializeContainer(Container container)
        {
            // Register your classes (anything other than the MVC controllers)
            // For instance:
            // container.Register<IUserRepository, SqlUserRepository>();
        }
    }

Happy Coding!

Custom SimpleInjector Dependency Resolver For Sitecore MVC

UPDATE: 9/17/2015 The code below has been updated in a newer blog post, changes to DI in Sitecore 8.1. After I wrote this post, Steven van Deursen (@dot_NET_Junkie), one of the creators behind SimpleInjector wrote to me to show that there is a better way to do this so that it doesn’t affect upgrades to SimpleInjector for v3, and in the future. Below code will still work, but if you upgrade to v3, you’ll need to change to how it is written in the other post.

 

Dependency Injection – it has been discussed quite a lot in the Sitecore community recently, and as usual, there are many different viewpoints of how it should be implemented. If you are wondering why you should use Dependency Injection in the first place, read:

Once you get through all of that and you are on board, you can start to implement some of this in your Sitecore Implementation.

But – my code works fine…

It probably does – for now. If you went through the above, the key benefit is flexibility. The business sponsor of a Sitecore project is usually the Marketing department of a company, so expect a lot of changes. If the system is built in a way these changes can be implemented without much fuss, you’ll save yourself a lot of headaches, and your marketing department will love you.

DI in the Sitecore Community

This blog post is a little overdue, but I’ve seen in recent times some discussion about how to implement, what IoC container to use, etc. As stated by Anders Laub in his post Simple IoC container using only the Sitecore API, the opinions on this can be religiously charged, almost fanatic. This post presents the case of not adding a third party IoC framework into an already complicated project – instead use the Sitecore API as a framework for your IoC. There are a lot of fans of using the Sitecore API as the IoC – Mike Reynolds has written about it, Leverage the Sitecore Configuration Factory: Inject Dependencies Through Class Constructors and Leverage the Sitecore Configuration Factory: Populate Class Properties with Instances of Types Defined in Configuration.

You can leverage third-party frameworks, as well – Glass Mapper, a popular ORM for Sitecore, comes with Castle Windsor as the IoC; Cris van de Luitgaarden wrote about Using Castle Windsor with Sitecore. There are plenty of third-party frameworks and they vary in implementation methods and speed. Read this for a good comparison.

I am a very big fan of K.I.S.S (keep it simple, stupid) – so my initial instinct is to always implement a solution that I can understand after a few months, or anyone who looks at the code can grasp immediately. There is a very good article (Also by Mark Seemann) about When to Use DI. So, given the problem you are trying to solve, there may not even be a need to introduce DI. But using a good DI framework – whether its poor man’s DI, or the Sitecore Configuration Factory, or a Third-Party Framework, the goal should be easy maintenance and easy growth/expansion. Over the years, I’ve used poor man’s Di many times, but recently started to look into some other frameworks.

Why Simpleinjector?

One of the things I didn’t like about my poor man’s DI implementation is that it mimic’ed the the Service Locater Pattern, and I would need to manually resolve my implementations. The Service Locator pattern also invokes somewhat of a fanatical debate – but what I didn’t like about it was that I would need to have a direct reference to it in the classes in my business layer.

I looked into some of the third party frameworks, and the first one that stuck out in the MVC references was ninject. I tried ninject for a bit, but the performance was really slow. I looked into Castle Windsor, too, but thought it was overkill for what I needed. I’ve heard good things about Autofac, but I’m not too familiar with it. I then looked into Simpleinjector, and it seemed to fit the bill perfectly. It was simple and light, and if needed, I could rip it out of my solution pretty easily and replace it with something else. Moreover, since I can wire up the container at application start, I don’t have to manually find each implementation, which was the key benefit.

Some implementation Issues

The implementation method for Simpleinjector in a MVC project is pretty simple – https://simpleinjector.readthedocs.org/en/latest/quickstart.html.

In an MVC project, you need to initialize your container at application start. The class that Simpleinjector provides for you out of the box looks something like this:


public static class SimpleInjectorInitializer
    {
        
        /// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
        public static void Initialize()
        {
            // Did you know the container can diagnose your configuration? 
            // Go to: https://simpleinjector.org/diagnostics
            var container = new Container();
            
            InitializeContainer(container);

            container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
            
            container.Verify();

            DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
        }
     
        private static void InitializeContainer(Container container)
        {
            InjectorResolver.RegisterImplementations(container);

            // For instance:
            // container.Register<IUserRepository, SqlUserRepository>();
        }
    }

SimpleInjectorDependencyResolver implements IDependencyResolver, which resolves the concrete implementations. Out of the box, this works great. But some browsing around, I started getting errors like this:

15212 23:25:49 ERROR Application error.
Exception: Sitecore.Mvc.Diagnostics.ControllerCreationException
Message: Could not create controller: 'Tests'. 
Source: Sitecore.Mvc
   at Sitecore.Mvc.Controllers.SitecoreControllerFactory.CreateController(RequestContext requestContext, String controllerName)
   at System.Web.Mvc.MvcHandler.ProcessRequestInit(HttpContextBase httpContext, IController& controller, IControllerFactory& factory)
   at System.Web.Mvc.MvcHandler.BeginProcessRequest(HttpContextBase httpContext, AsyncCallback callback, Object state)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
Nested Exception
Exception: System.InvalidOperationException
Message: An error occurred when trying to create a controller of type 'Sitecore.ContentTesting.Requests.Controllers.Optimization.TestsController'. Make sure that the controller has a parameterless public constructor.
Source: System.Web.Mvc
   at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)
   at System.Web.Mvc.DefaultControllerFactory.CreateController(RequestContext requestContext, String controllerName)
   at Sitecore.Apps.TagInjection.DependencyResolver.TagInjectionControllerFactory.CreateController(RequestContext requestContext, String controllerName)
   at Sitecore.Mvc.Controllers.SitecoreControllerFactory.CreateController(RequestContext requestContext, String controllerName)
Nested Exception
Exception: SimpleInjector.ActivationException
Message: No registration for type TestsController could be found and an implicit registration could not be made. For the container to be able to create TestsController, it should contain exactly one public constructor, but it has 2.
Source: SimpleInjector
   at SimpleInjector.Container.ThrowMissingInstanceProducerException(Type serviceType)
   at SimpleInjector.Container.GetInstanceFromProducer(InstanceProducer instanceProducer, Type serviceType)
   at SimpleInjector.Container.GetInstance(Type serviceType)
   at System.Web.Mvc.DefaultControllerFactory.DefaultControllerActivator.Create(RequestContext requestContext, Type controllerType)

Turns out, once you initialize the application with the SimpleInjectorDependencyResolver container, ALL controllers are being resolved with SimpleInjectorDependencyResolver – even implementations that you never registered in your container, and thus the error.

The Solution

Since SimpleInjectorDependencyResolver isn’t aware of the Sitecore controllers, we have to make our own class that implements IDependencyResolver:

public class CustomDependencyResolver : IDependencyResolver
    {

        public Container Container { get; private set; }

        public CustomDependencyResolver(Container container)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }
            this.Container = container;
        }

        public object GetService(Type serviceType)
        {
            if (serviceType.Assembly.FullName.StartsWith("Sitecore"))
            {
                return Sitecore.Mvc.Helpers.TypeHelper.CreateObject<IController>(serviceType, new object[0]);
            }
            if (!serviceType.IsAbstract && typeof(IController).IsAssignableFrom(serviceType))
            {
                return this.Container.GetInstance(serviceType);
            }
            return ((IServiceProvider)this.Container).GetService(serviceType);
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            return this.Container.GetAllInstances(serviceType);
        }

    }

What this is doing is essentially implementing a custom GetService method, which checks to see if the assemblyname begins with Sitecore. If it does, it uses Sitecore MVC helpers to create the instance. If not, then it checks to see if the serviceType being requested is abstract/interface – then it gets the concrete implementation from the SimpleInjector container – the ones that we registered. And lastly, once this class is done, instead of using SimpleInjectorDependencyResolver in the Application Initialize, we use our class CustomDependencyResolver:

Instead of this:

DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));

..do this:

DependencyResolver.SetResolver(new CustomDependencyResolver(container));

All the errors for any other controller instantiation should now go away.

Conclusion

Dependency Injection and the choice of DI frameworks remain a hot topic still. The issue I faced is one argument against using a third party framework, but SimpleInjector is light enough that it doesn’t intrude too much into my application. I’m hoping this can help anybody who uses SimpleInjector. The bottomline is, you really have to take a good look at your application before you make a choice to commit to an IoC framework, because some of the more complicated ones can really be a large commitment, so choose wisely!