Using the App Model for deploying Site Collections and Sites

Using the App Model for deploying Site Collections and Sites

Last weekend I had the opportunity to do a session with Waldek Mastykarz on Leveraging the new Application Model for structured and repeatable deployments, you can find the slides on SlideShare: Leveraging the new Application Model for structured and repeatable deployments . While preparing for this session of the last few weeks we tried to apply the App Model in real life scenario’s to achieve structured and repeatable deployments on Office 365. Based on these experiences Waldek already posted an article on Leveraging the SharePoint 2013 App Model for structured and repeatable deployments and promised that we would share all samples we walked through during the session. In this first part we will look into deploying and creating Site Collections and Sites through the App Model.

Creating Site Collections

As the app model introduces a new permission model as well there are a few things to keep in mind when designing your new app. In order to create new Site Collections you are required to have FullControl permissions on the Tenant. While for creating sub sites you will only need Manage permissions. Besides that you will need a reference to the Tenant assembly: Microsoft.Online.SharePoint.Client.Tenant. If you cannot find it you can download the Client Components SDK.

With this reference you can use the context to construct a tenant object. However you will need the tenant admin as a context and not the client context that is present in your app. To construct the new admin context you will need to retrieve the tenant admin URL so we can retrieve the correct token. As creating a new Site Collection can take up to 15 minutes running this from within a UI threat would not be a good idea. When running this code from something else then the UI threat you will require the AppOnlyAccessToken since the account running the process will most likely not have tenant admin permissions. With the app token we can then construct the corrected admin context.

Site site = clientContext.Site;
clientContext.Load(site, s => s.Url);
clientContext.ExecuteQuery();

// Get Client Context for tenant admin site
Uri siteUri = new Uri(site.Url);
string tenantAdminUrl = String.Format("https://{0}-admin.sharepoint.com", siteUri.Host.Substring(0, siteUri.Host.IndexOf('.')));
Uri tenantAdminUri = new Uri(tenantAdminUrl);
var realm = TokenHelper.GetRealmFromTargetUrl(tenantAdminUri);

// GetAppOnlyAccessToken is required if you run in something else then the UI thread! 
var token = TokenHelper.GetAppOnlyAccessToken(TokenHelper.SharePointPrincipal, tenantAdminUri.Authority, realm).AccessToken;
ClientContext adminContext = TokenHelper.GetClientContextWithAccessToken(tenantAdminUri.ToString(), token);

Once the client context that is based on the tenant admin is available you can construct a new Tenant object, that can be used to create new operations. When creating a new operation to create a site you are required to pass certain settings, and if that is done properly you can retrieve the status and polling interval. Based on these you can then poll to check whether the operation is finished or not. As pointed out creating a new Site Collection can take up to 15 minutes so waiting for your Site Collection to be ready is mandatory if you need to provision more then just a Site Collection. To do so you can simply check the status of the operation every few seconds. If you are polling for changes you have to do two things, one is to refresh the load and then execute the query again. You can either set a custom interval to wait, but there is a default available as well (15 seconds). If you check the status you might encounter an Web Exception as the context get closed after completion.

Tenant tenant = new Tenant(adminContext);
SpoOperation op = tenant.CreateSite(new SiteCreationProperties {
    Title = "SPSNL14",
    Url = String.Format("https://{0}/sites/SPSNL14-2", siteUri.Host),
    Template = "STS#0",
    Lcid = 1033,
    Owner = "appie@digiwijs.nl"
});

adminContext.Load(tenant);
adminContext.Load(op, i => i.IsComplete, i => i.PollingInterval);
adminContext.ExecuteQuery();

while (!op.IsComplete) {
    System.Threading.Thread.Sleep(op.PollingInterval);
    op.RefreshLoad();

    if (!op.IsComplete) {
       try {
          adminContext.ExecuteQuery();
       }
       catch (WebException) {
            // ctx connection get's closed after action completed...calling ExecuteQuery again can return an error that we can ignore
        }
    }
}

Creating Sites

For creating new sub sites the sample is even easier. By creating a new WebCreationInformation object with the proper parameters will result in a new sub web.

Web rootWeb = clientContext.Site.RootWeb;

rootWeb.Webs.Add(new WebCreationInformation {
    Title = "Sessions",
    Description = "SPSNL14 Sessions",
    Url = "sessions",
    WebTemplate = "STS#0",
    UseSamePermissionsAsParentSite = true,
    Language = 1033
});

clientContext.ExecuteQuery();

You can download the Sample App for SharePoint(227KB, ZIP).

Leave a Reply