Posted on Oct 20, 2011

In this post, I'm going to describe how to create templates in SharePoint 2010. One of the reasons to create templates programmatically may be to perform a custom action once a template is created as a hypothetical event handler OnTemplateCreated does not exist in SharePoint. Thanks to the Refrector utility we can peek into SharePoint code and create templates the way SharePoint does it. 


As an example of a custom action, I'm going to add a new list item to a custom list MyTemplates located in the root website. The list has only one column - the Title.

Let's look at the user interface. It may have similar look and feel as the built-in SharePoint form (a screenshot below).

Save Template in SharePoint 2010

There are the following fields on this form:

  • txtFileName
  • txtTemplateName
  • txtTemplateDescription
  • chkIncludeContent

Creating list templates is quite different than creating site templates. Let's look how to create list templates first.

Creating list templates programmatically

I use a method SaveAsTemplate of the SPList class. At first, I need to have an instance of a list that I want to save as a template. One of the methods to do that is to pass the list id (a GUID) in a query string (ListId=GUID) and then grab the list from the list collection of the current website. Once I have the list I save it as a template by calling the SaveAsTemplate method. After that, I can perform any custom actions.

// Read values from the user interface.
string solutionFileName = this.txtFileName.Text.Trim() + ".stp";
string templateName = this.txtTemplateName.Text.Trim();
string templateDesc = this.txtTemplateDescription.Text.Trim();
bool includeContent = this.chkIncludeContent.Checked;

// Get all lists in the current web context.
SPWeb contextWeb = SPControl.GetContextWeb(this.Context);
SPListCollection lists = contextWeb.Lists;

// Determine the GUID of the current list.
Guid listId = new Guid(Request["ListId"]);
    
// Grab the list form the list collection.
SPList list = lists[listId];

// Save the list as a template.
list.SaveAsTemplate(solutionFileName, templateName == "" ? null : templateName, templateDesc == "" ? null : templateDesc, includeContent);

// Perform any custom action, for example add a new list item to the MyTemplates list.
try
{
    rootWeb.AllowUnsafeUpdates = true;

    SPListItemCollection items = SPContext.Current.Site.RootWeb.Lists["MyTemplates"].Items;
    SPListItem item = items.Add();
    item["Title"] = templateName;
    item.Update();
}
finally
{
    rootWeb.AllowUnsafeUpdates = false;
}

Creating site templates programmatically

Creating site templates is accomplished using different methods than creating list templates. First of all, I use a static method SPSolutionExporter.ExportWebToGallery to create the template. The code is also wrapped into a SPLongOperation object as creating site templates may be a time-consuming operation.

Once SharePoint completes creating the site template, control is redirected to a custom page CustomActions.aspx thanks to the End method of the SPLongOperation object. On that page, any custom action can be performed. In our case, I add a list item to the custom list MyTemplates in the same fashion as I did for the list template.

// Read values from the user interface.
string solutionFileName = this.txtFileName.Text.Trim() + ".wsp";
string templateName = this.txtTemplateName.Text.Trim();
string templateDesc = this.txtTemplateDescription.Text.Trim();
bool includeContent = this.chkIncludeContent.Checked;

// Get the current context. It's needed in the SPSolutionExporter.ExportWebToGallery method.
SPWeb contextWeb = SPControl.GetContextWeb(this.Context);

SPSecurity.RunWithElevatedPrivileges(delegate()
{
    using (SPSite site = new SPSite(contextWeb.Site.Url))
    {
        using (SPWeb web = site.OpenWeb(contextWeb.ID))
        {
            // Instantiate the SPLongOperation object.
            using (SPLongOperation operation = new SPLongOperation(this.Page))
            {
                // Provide the text displayed in bold
                operation.LeadingHTML = "Long running operation is being performed";

                // Provide the normal formatted text
                operation.TrailingHTML = "Please wait while your request is being performed. This can take a couple of seconds.";

                web.AllowUnsafeUpdates = true;
                web.Site.RootWeb.AllowUnsafeUpdates = true;
                    
                operation.Begin();

                // Save the site template to the template gallery.
                SPSolutionExporter.ExportWebToGallery(contextWeb, solutionFileName, templateName, templateDesc, SPSolutionExporter.ExportMode.FullReuse, includeContent));

                // Encode the template title.
                string queryString = " TemplateTitle=" + SPHttpUtility.UrlKeyValueEncode(templateTitle);

                // Redirect to the CustomActions.aspx page passing the template title in the query string.
                operation.End("CustomActions.aspx", SPRedirectFlags.RelativeToLayoutsPage, this.Context, queryString);
            }
        }
    }
});

The code in the CustomActions.aspx page is the same as for the list template except it should be located within an event handler such as Page_Load:

// Get the template name from the query string.
string templateName = SPHttpUtility.UrlKeyValueDecode(Request.QueryString["TemplateName"]);

// Perform any custom action. For example, add a new list item to the MyTemplates list.
try
{
    rootWeb.AllowUnsafeUpdates = true;

    SPListItemCollection items = SPContext.Current.Site.RootWeb.Lists["MyTemplates"].Items;
    SPListItem item = items.Add();
    item["Title"] = templateName;
    item.Update();
}
finally
{
    rootWeb.AllowUnsafeUpdates = false;
}

That's all for now. Happy coding.