Deployment Approaches for SharePoint 2013 Online & On Premises – Presentation

I recently presented at the Wellington, New Zealand SharePoint User Group on deployment approaches for SharePoint 2013 Online and on premises (transcript below).

I discussed the approaches Provoke Solutions Wellington have taken in the past for deployments in SharePoint 2007 and 2010 and how we got to a pretty comfortable position before 2013 came out. I then go over three different approaches we have taken for SharePoint 2013 deployments including on premises and SharePoint Online, covering a bit of CSOM, design manager, custom CMDlets, sandboxed/farm solutions and more.

In the conclusion I discuss how custom CMDlets are the way of the future for deployments due to the fact that they can run both on premises and on SharePoint online, but also because Microsoft are supporting this approach. Check out the Office 365 Patterns and Practices and also check out Wayne Ewington's Tech Ed 2014 presentation where he discusses new approaches for avoiding farm solutions. Provoke also have a downloadable CMDlets library you can use, find out more here.
 

Presentation Contents:

Overview
The Past
The Present

The Future
Conclusion


Overview

SharePoint has never been the easiest platform to code against or deploy to and often involves a lot of harsh lessons for any new SharePoint developers. It can be easy to go over time and budget if you haven’t planned and accounted for deployments appropriately.

Building a robust deployment approach takes experience, research and time as I will explain through the presentation. But with the right approach you can make development, testing and releases a less stressful process.

SharePoint solution releases can have quite a few moving parts, for this presentation I have kept it pretty simple, only covering basic assets such as master pages, content types etc and creating site structures.

So, let’s talk a little bit about the past.

The Past

SharePoint 2007 and 2010 had many challenges, but the one great thing about them both was farm solutions! Writing C# code for everything was close enough to ASP.Net development that it wasn’t too hard to pick up once you got your head around some basic SharePoint fundamentals. I may be simplifying this a little, but you get the idea.

Over this 5 years, Provoke built an awesome site provisioning class library called Fluent Creation Extensions. This code library allowed you to quickly generate site columns, content types, site structures and more. We used this library in event receivers and console applications for releases and updates inside farm solutions which deployed site assets directly to the SharePoint hive. As far as I’m aware we didn’t use Sandboxed solutions at all during this time.

Here is an example use of the creation library at work (click to enlarge):

As you can see in this specific example, we are quickly and easily defining a new page content type with taxonomy fields, date fields, choice field etc. We are also specifying default values, internal names and the content type group. This allowed most of the SharePoint interactions and cumbersome coding tasks to be abstracted away.

When I joined Provoke, I had been working with SharePoint for a while but mostly on products, not intranets. So when I started work on some 2010 enhancements for a client, I used the Fluent Extensions along with some code samples from previous projects and was able to get something up and running quickly. The development for this project went extremely smoothly and testing hours were well under, deployments also went in without a hitch. The 5 years of sweat, tears and experience from others had paid off.

Everything was awesome… Until SharePoint 2013 and SharePoint online came out. This brings us to the next part of the journey.

The Present

With SharePoint 2013 came a lot of change, heaps of new features and new approaches for deploying structure and assets. We knew that farm solutions were now undesirable and we had to start looking at alternatives. In the past we had not only provisioned sites with server side code, but also built all webparts with it. We now had to think about how we could use out of the box components and strategies.
 

FIRST APPROACH – Design Manager, Sandboxed Solutions, XML + PowerShell, and a little bit of CSOM

So how did we first approach 2013? Note that this first approach is only for on premises.

We started only using Sandboxed solutions for deploying nearly everything including web parts, content types, fields and css. We also started using the new Design Manager for page layouts, master pages and their associated content types and fields.

This new approach had a number of disadvantages, starting with Design Manager. Both our office and the Auckland office encountered a number of issues with using the packages it created in deployments and we decided it wasn’t reliable enough to use any longer.

The other disadvantage to this approach was using such a huge amount of PowerShell. PowerShell is amazing, but it wasn’t the easiest to debug and just didn’t seem the right tool for writing large deployments. The other obvious disadvantage to this approach was we were using exclusively on premises out of the box cmdlets and therefore couldn’t re-use it with online sites. This was early days though and the learning continued.

The XML file specifies the structure of the site and subsites and includes for example which sandboxed solutions to install, which features to activate, which pages to create, managed metadata set up etc. We used a small amount of CSOM in the form of custom CMDlets for connecting managed metadata fields.

Design Manager and PowerShell
 

SECOND APPROACH – CSOM library, Console Application and Sandboxed Solutions

Our next approach involved a few changes. First off we removed Design Manager packages – we still used it for generating page layouts and master pages, but extracted the code files into our own sandboxed solutions.

We also built a CSOM class library and a C# console application. This was starting to get a bit more like our beloved farm solution approach.

This new approach had a few benefits including the ability to run the code against SharePoint online and developers having a more familiar environment to develop and debug in. We used a similar XML structure for defining the site creation.

csom and console apps
 

THIRD APPROACH – Custom CMDlets, CSOM and Sandboxed Solutions

By this stage we were starting to build some good momentum and experience around SharePoint 2013. But there was still progress to be made.

We made the choice to follow the Auckland office’s lead and use custom PowerShell cmdlets with CSOM. This would give Provoke a more unified approach to SharePoint deployments as the Wellington office has always been more code heavy while the Auckland office favoured more out of the box approaches.

Custom powershell cmdlets

This approach has worked magic for our latest releases and we were able to re-use a lot of the tried and tested code from our CSOM library, meaning it wasn’t all wasted. We are heading more towards a point where we have the best possible deployment approach.

Following is an example of creating custom list level permissions

XML structure

<Security>
   <AddCustomListPermissions>
      <CustomListPermission ListTitle="Pages" Group="News &amp; Events" PermissionLevel="Contribute"  />
   </AddCustomListPermissions>
</Security>


PowerShell

function processCustomListPermissions($web, $customListPermissions)
{
    if ($customListPermissions.HasChildNodes)
    {
        foreach($customListPermission in $customListPermissions.CustomListPermission)
        {
            write-host "Adding new permission level to list " $customListPermission.ListTitle $customListPermission.Group $customListPermission.PermissionLevel
            Add-SPOListPermission $web $customListPermission.ListTitle $customListPermission.Group $customListPermission.PermissionLevel
        }
    }
}


Custom CMDlet

    /// <summary>
    /// Breaks inheritance on a list and adds/removes specified groups with specified security level
    /// </summary>
    /// <remarks>
    /// <strong>Arguments<br/></strong>
    /// <strong>Parent (Web):</strong> The parent Web under which the list exists eg. $ctx.Web<br/>
    /// <strong>ListTitle (String):</strong> List Title<br/>
    /// <strong>Group (String):</strong> The group to add or remove<br/>
    /// <strong>PermissionLevel (String):</strong> The permission level to add the group as<br/>
    /// </remarks>
    /// <example><code>Add-SPOListPermission $ctx.Web "List Title" "Group Name" "Contribute"</code></example>
    [Cmdlet(VerbsCommon.Add, "SPOListPermission")]
    public class AddSPOListPermission : PSCmdlet
    {
        [Parameter(Position = 0), ValidateNotNullOrEmpty]
        public Web Parent { get; set; }

        [Parameter(Position = 1), ValidateNotNullOrEmpty]
        public string ListTitle { get; set; }

        [Parameter(Position = 2), ValidateNotNullOrEmpty]
        public string Group { get; set; }

        [Parameter(Position = 3), ValidateNotNullOrEmpty]
        public string PermissionLevel { get; set; }

        protected override void ProcessRecord()
        {
            List list = null;

            var lists = Parent.Lists;
            Parent.Context.Load(lists, l => l.Include(x => x.Title));
            Parent.Context.ExecuteQuery();

            list = lists.Cast<List>().SingleOrDefault(l => l.Title.Equals(ListTitle));

            if (list != null)
            {
                list.BreakRoleInheritance(true, false);
                Parent.Context.ExecuteQuery();

                var group = Parent.SiteGroups.GetByName(Group);
                var role = Parent.RoleDefinitions.GetByName(PermissionLevel);
                Parent.Context.Load(role);
                Parent.Context.Load(group);
                Parent.Context.ExecuteQuery();

                if (group != null)
                {
                    if (role != null)
                    {
                        var roleBinding = new RoleDefinitionBindingCollection(Parent.Context);
                        roleBinding.Add(role);
                        list.RoleAssignments.Add(group, roleBinding);
                        Parent.Context.ExecuteQuery();
                    }
                    else
                        Console.WriteLine(String.Format("Permission level '{0}' not found", PermissionLevel));
                }
                else
                    Console.WriteLine(String.Format("Group '{0}' not found", Group));
            }
            else
                Console.WriteLine(String.Format("List '{0}' not found", ListTitle));
        }
    }

This brings us to the next phase of our journey

The Future

We will continue to invest time and effort in researching and developing more efficient and robust deployment approaches. We will be sticking with the CMDlets approach which has proven a good decision after watching a presentation Wayne Ewington gave at TechEd this month. Microsoft are pushing for avoiding any solution files, including sandboxed. This means building CMDlets for deploying content types and fields as well as for uploading site assets. Luckily as part of this push there are a number of CMDlets available for everyone to use. These are written by community members but endorsed by Microsoft engineers.

We will be looking at these CMDlets alongside our own to determine whether we should use these CMDlets, our own or possibly a combination.

Conclusion

Using custom CMDlets is currently the best approach for deployments.

There are many challenges ahead, one of the biggest being the rapidly changing SharePoint online environment. There’s always new functionality and enhancements going in, which means keeping an eye on the relevance of your deployment code. It also introduces the complexity of maintaining CMDlets which will work for on premises AND online. 

It’s pretty exciting times in the SharePoint world at the moment.

 

Leave a Reply

Your email address will not be published. Required fields are marked *