X

This site uses cookies and by using the site you are consenting to this. We utilize cookies to optimize our brand’s web presence and website experience. To learn more about cookies, click here to read our privacy statement.

SharePoint 2013 Autohosted App – List/Library Provisioning

At my current client we have run into issues with creating templates (web or list) that include lists with custom content types, columns, and views.  We implemented a content type hub and for some reason the child content type on the list from a template does not sync properly leaving behind a mess.  As a work around solution I created an autohosted app that creates a new list instance, programmatically attaching content types, creating views, and setting list settings that are available through the client site object model.  I will demonstrate the methods on how to create the list and also cover some caveats when creating an autohosted app.

Create a User Interface for Creating a New List

DocumentLibraryUI

In the default.aspx in the app design there is a form to accept the name of the list and description. These values will be used as parameters for creating the list.  I created buttons to handle the events for creating the list and also to cancel the request and redirect to the host web.

App Permissions

Web – Manage (Minimum permission to be able to create a new list or library on a site)

Site Collection – Read (in order to properly read the content types that are available on the site collection level to attach to the list)

List Creation

Since this is an autohosted app we will be using CSOM to code the logic to create the list.  I make sure that I load both the web and RootWeb object to ensure that this will create the list on both a subsite and top site site collection level.  This is necessary for adding content types to the list that are subscribed from a content type hub.  Place the following code in the onclick event of the the create button.

using (var clientContext = TokenHelper.GetClientContextWithContextToken(hostWeb, contextToken, Request.Url.Authority))
{

clientContext.Load(clientContext.Site, s => s.RootWeb);
var rootWeb = clientContext.Site.RootWeb;
clientContext.Load(rootWeb, web => web.Lists);
clientContext.Load(rootWeb, web => web.ContentTypes);
clientContext.Load(clientContext.Web, web => web.Url);
clientContext.ExecuteQuery();

//get the title from the text boxes
string listTitle = txtListTitle.Text.Trim();
string listDesc = txtDescription.Text.Trim();

//Create List Creation Information Object for creating the new list instance
ListCreationInformation lci = new ListCreationInformation();
lci.Title = listTitle;
if (!string.IsNullOrEmpty(listDesc))
{
lci.Description = listDesc;
}
//This is the base template type. 101 is for a standard Document Library.
lci.TemplateType = 101;
List newLib = clientContext.Web.Lists.Add(lci);
clientContext.Load(newLib);
clientContext.ExecuteQuery();

//Set various settings that are available in the API
//Get the newly created instance of the list
List teamDocs = clientContext.Web.Lists.GetByTitle(newLib.Title);
clientContext.Load(teamDocs);

teamDocs.EnableVersioning = true;
teamDocs.EnableFolderCreation = false;
teamDocs.ContentTypesEnabled = true;
teamDocs.Update();

//Insert code to add content type and create views here

clientContext.ExecuteQuery();
Response.Redirect(clientContext.Web.Url + “/” + teamDocs.Title);

}

Add Custom Content Types and Remove Default Content Type

The following snippet can be included in the onclick event to add a content type and also remove default content type using CSOM.

//Get the content type object from the top level site.  This is why we are using the RootWeb Object
var customCT = (from ContentType ftype in context.Site.RootWeb.ContentTypes where ftype.Name == “Custom Content Type Name”  select ftype).FirstOrDefault();

//Add the existing content type
list.ContentTypes.AddExistingContentType(customCT );
context.Load(list, l => l.ContentTypes);
context.ExecuteQuery();
//Remove Default Content Type
var defaultCT = (from ContentType ct in list.ContentTypes where ct.Name == “Document” select ct).FirstOrDefault();
defaultCT.DeleteObject();

Create and Modify List Views

This snippet will demonstrate how to modify existing views and how to create new views.

//Modify All Documents View.  Add columns, remove columns, set row limit, query
var defaultView = list.Views.GetByTitle(“All Documents”);
defaultView.ViewFields.Remove(“Modified”);
defaultView.ViewFields.Add(“Editor”);
defaultView.ViewFields.Add(“TaxKeyword”);
defaultView.ViewFields.Add(“CheckoutUser”);
defaultView.ViewFields.Add(“ReviewDate”);
defaultView.ViewQuery = @”<OrderBy><FieldRef Name=’LinkFilename’ /></OrderBy>”;
defaultView.RowLimit = 50;
defaultView.Update();

//Create a new view, set columns,query,row limit,view type kind, view settings
//Get ViewType of the default view to be used as a parameter for ViewTypeKind
clientContext.Load(defaultView, v => v.ViewType);
clientContext.ExecuteQuery();

ViewCreationInformation vciCheckedOut = new ViewCreationInformation();
vciCheckedOut.Title = “Checked Out To Me”;
vciCheckedOut.ViewTypeKind = (ViewType)Enum.Parse(typeof(ViewType), defaultView.ViewType, true);
vciCheckedOut.RowLimit = 50;

string[] checkedViewFields = { “DocIcon”, “LinkFilename”, “Modified”, “Editor”, “TaxKeyword”, “CheckoutUser”, DocStatus”, “DocReviewDate” };
vciCheckedOut.ViewFields = checkedViewFields;
vciCheckedOut.PersonalView = false;
vciCheckedOut.Paged = true;
vciCheckedOut.Query = @”<OrderBy><FieldRef Name=’LinkFilename’ /></OrderBy><Where><Eq><FieldRef Name=’CheckoutUser’ /><Value Type=’Integer’><UserID Type=’Integer’/></Value></Eq></Where>”;
list.Views.Add(vciCheckedOut);

Caveats I Ran Into

Storing the context
In order to have button post back functionality, the context needs to be preserved after the post back happens.  The context can be stored as a View State Parameter.  In the class, add the following before page load event.

//Store Context Token in ViewState to persist after postback caused by buttons
public string contextToken
{
get
{
return ViewState[“ctxToken”].ToString();
}
set
{
ViewState[“ctxToken”] = value;
}

}

//global variable to store the host web URL
public string hostWeb;

In the page load event add the following to ensure the context is loaded properly during the first postback and is persisted.

//Get the Host Web URL
hostWeb = Page.Request[“SPHostUrl”];

//store the context in the view state
if (!IsPostBack)
{
contextToken = TokenHelper.GetContextTokenFromRequest(Page.Request);
}

Using Validation Controls

When using validation controls, the validator control did not trigger.  In order for the validation controls to function, an entry must be added to the app’s web.config file.  In the <appSettings> section add the following

<add key=”ValidationSettings:UnobtrusiveValidationMode” value=”None” />

Certain List Settings Not Available in the API

There are certain settings that are either not available in the API or I could not find the equivalent code in CSOM.  If you know what they are please comment!

  • Rating Settings
  • Open forms in dialog
  • Number of versions to keep
  • Certain view settings

Conclusion

This is a way to use SharePoint apps in the cloud to create lists that can be recreated tenant-wide when list templates and web templates cannot get the job done.  Although some settings may not be set programmatically, this app can get you 90% of the the lists created without having to manually configure the list each time.