Sunday 12 December 2010

N2CMS MVC and how to create a configurable MasterPage option

One of the most common questions on the N2CMS forums seems to be how to make it possible to be able to select a master page. In the past when I've worked on cms driven sites the templates have been relatively straightforward - the homepage has had a unique design whilst the others have had a set template. This was quite easy to do as I just created my own class which derived from the StartPage class and then created it's own HTML without using the main MasterPage. Simple, but effective.

However, recently I've been asked to convert an existing Sharepoint site to the MVC version of N2. This has been quite interesting to do and one of the areas I've had to work on is how to give the user the option of which master page template to use. I can't do this statically and because there are a number of templates on the current Sharepoint site it's possible that users may need to change page templates "on the fly".

I'm not going to go to deep in to the workings of this - it's probably easier to fire up N2 MVC and step through the code. I'm going to give you a step-by-step tutorial to get it working!

I'd like to thank the guys on this discussion on the N2CMS forum (n2cms.codeplex.com/discussions?size=2147483647) for providing the inspiration for this. I can't find the exact post however.

Step 1:
Make sure you download the latest v2.1rc MVC version of the site and make sure you copy the DLLs in the library folder into the bin folder of the N2CMS folder. If you don't do this with then you might get an error when you first try to start the site.

Step 2:


In the services folder, open the ThemedMasterViewEngine.cs file. In that there's a method which tries to determine which Master page to use based on theme or uses the  there's a class which checks to see what master page to use.



public class ThemedMasterViewEngine : WebFormViewEngine
{
        // You should change the "TwoColumnLayout.master" to be your default template
        string masterPageFile = "~/Views/Shared/TwoColumnLayout.master";

public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
{
if (!controllerContext.IsChildAction)
{
if (string.IsNullOrEmpty(masterName))
masterName = masterPageFile;

var root = Find.Closest<StartPage>(controllerContext.RouteData.CurrentPage()) ?? Find.ClosestStartPage;
if (root != null)
{
string theme = root.Theme;
if (!string.IsNullOrEmpty(theme))
{
string potentialMaster = string.Format("~/Views/Shared/{0}.master", theme);
if (base.FileExists(controllerContext, potentialMaster))
{
masterName = potentialMaster;
}
}
}
}

return base.FindView(controllerContext, viewName, masterName, useCache);
}
}

Step 3:

In the models/pages folder there's a ContentPageBase.cs class. We're going to change this to add an enum for the name of the page templates and add a property for any page which derives from the ContentPageBase (which is all of them) which allows you to select a template and puts it under the Advanced tab.

Open /Models/Pages/ContentPageBaseup and add this code:

        public enum PageTemplates
        {
            MyHomePage,
            TwoColumnLayout
        }

        [EditableEnum("Page layout", 60, typeof(PageTemplates), ContainerName = Tabs.Advanced)]
        public virtual PageTemplates PageLayout
        {
            get { return (PageTemplates)(GetDetail("PageLayout") ?? PageTemplates.TwoColumnLayout); }
            set
            {
                SetDetail("PageLayout", value, PageTemplates.TwoColumnLayout);
            }
        }

Step 4:

In the controllers folder, open up the TemplatesControllerBase.cs file. We're going to add some code in here which tries to get the name of the PageLayout from the page and sets the master page. Find the method below (be careful - there's a few overloads of it) and replace the method with this code:

protected override ViewResult View(string viewName, string masterName, object model)
{
CheckForPageRender(model);

            model = model ?? CurrentItem;
            if (model != null)
            {
                var item = model as N2.Templates.Mvc.Models.Pages.ContentPageBase;
                if (!string.IsNullOrEmpty(item.PageLayout.ToString()))
                {
                    masterName = item.PageLayout.ToString();
                }
            }

return base.View(viewName, masterName, model ?? CurrentItem);
}

Step 5:

I think this might be an oversight in the n2 release, but I've found I have to add this line into the web.config in the n2 editing folder:

<httpRuntime requestValidationMode="2.0" />

Otherwise I get an error when I try to change the page layout.

Step 6:

If you start up your site, and select "Edit" on any page you will find that under the "Advanced" tab you have a drop down list of layouts. If you change this you will be able to change the master page used on the site!

Friday 3 December 2010

New version of N2CMS released

I don't know if you've seen on http://n2cms.codeplex.com/releases but v2.1rc has been released. I'd strongly recommend anyone to sign up for the release notifications on Codeplex for the code as this way you will get the latest versions as soon as they come out. On the page for the releases if you look on the right you'll see the button to set notification settings.

As you know, I've been doing tutorials for the web forms version of N2. If you read my earlier posts you'll have read that for beginners I'd recommended the web forms version to get started with because of the better templates that came with it - it was simply easier/quicker to create pages and items. This looks like it has changed with the new release and I am currently investigating the new changes so that I'll be able to comment on the web forms vs MVC projects.

Another reason to download the new version is that it now ships with documentation! Now, I've read the documentation and it's still not perfect nor complete but it's far better than the array of wikis, pages and dead pages that are on the web. So, if nothing else you have a much better starting point for v2.1 than you did with the earlier versions.

All that said, I still aim to continue writing on this blog. There's some new features in the new version which look very interesting such as templates. This will allow you to create templates of pages and subpages with pre-populated content. Very useful.

I think however, my focus will broaden somewhat to include my experiences of the N2 MVC. I also am intrigued by how we can extend the editor with jQuery and similar technologies.

For now though, have a look at the new version!