Programmatically Creating Content Databases and Site Collections

Even if SharePoint 2013 hype is all around us, and we love to play with SP 2013 – let’s be realistic, our daily bread is still with our 3 years old friend (or sometimes with even the older ones).

We had a following task (scenario) in the last days: a customer needs automated creation of Site Collections. But, since there is going to be lot of Site Collections, and since total data volume will go up to 20 TB in first 2-3 years, we needed, because of the SharePoint limits, to find a clever way of creating and adding new content databases on the fly, and creating new site collection in those databases.

Basically, we have configured thresholds – if in the “current” content database there is more than X site collections, or total data volume is over Y bytes, create a new content database, and store all future site collections in that new content database. Until that database also reaches the thresholds, and then… you get the point.

The following code does the trick. Note: it is recommended to execute it in the farm administrator context.

Step 1:  get the list of the existing content databases

 

// get all content databases
SPContentDatabaseCollection contentDbs = siteCollection.WebApplication.ContentDatabases;

In our case, content databases are all ending with the suffix "XZY”, where XYZ is nothing else but counter. E.g. “MyContentDatabase001”, “MyContentDatabase002”, “MyContentDatabase003”… etc. We search for the database with the highest index, and check it against (previously configured) thresholds.

Step 2:  get the status of the “last” (working) content database (db size, number of site collections)

 

bool createNewDb = false;

SPContentDatabase lastDatabase = contentDbs[contentDbs.Count-1];

if (
    lastDatabase.DiskSizeRequired > this.contentDatabaseMaxTresholdSize || 
    lastDatabase.Sites.Count >= lastDatabase.MaximumSiteCount
    )
{
    createNewDb = true;
}

After we have checked the database, and decided if we need to create a new one for our site collections, let’s do it if we need to:

Step 3: create a new content database

 

if (createNewDb)
    contentDatabase = siteCollection.WebApplication.ContentDatabases.Add(
        serverName, 
        newDbName, 
        username, 
        password, 
        warningSiteCollectionNumber, 
        maximumSiteCollectionsNumber, 
        0);
    										
    contentDatabase.Update();
    siteCollection.WebApplication.Update();
}

In the code above, you can leave username and password empty, if you want to use windows authentication. Parameters “warningSiteCollectionNumber” and “maximumSiteCollectionNumber” define number of site collections when administrator starts to get the warnings, and the maximal number of the site collections for this content database.

Step 4: create the site collection in the database

 

newSite = contentDatabase.Sites.Add(
    newSiteColectionUrl, 
    siteCollectionTitle, 
    siteCollectionDescription, 
    1033, 
    "MyTemplate#0", 
    firstAdminLogin, 
    firstAdminName, 
    firstAdminEmail, 
    secondAdminLogin, 
    secondAdminName, 
    secondAdminEmail);

// Let's add the upper limit for the site collection
SPQuota quota = new SPQuota();
quota.StorageMaximumLevel = maximumBytesForSiteCollection;
newSite.Quota = quota;

// And update the site collection and the content database
newSite.RootWeb.Update();
contentDatabase.Update();

As opposed to the “usual” way of creating site collections (WebApplication.Sites.Add), it is less known that we can create site collection directly from content database, as in this code sample. Since the content database belongs to a web application, it is obvious that the site collection will belong to that same web application. There are more overloads of this method, for example with only one site collection admin.

And that would be all. New site collection is created in a specific content database. On this way, you can control and govern the growth of your content databases, site collections, and all related parameters.

System.InvalidOperationException: Operation is not valid due to the current state of the object

Oh, yes. We did have another issue. Since this code was executed from a WCF web service, which has it’s own HttpContext (not the SharePoint one!), the code above has crashed each time we did anything with the SPContentDatabase (create, update, whatever…). And if you have HttpContext, SharePoint wants you to have a valid FormDigest control, it’s a security check. Which, in the WCF code, we obviously do not have.

So, to simulate the situation that we are outside the Sharepoint context (e.g. in a timer job, or in a console application), which would prevent SharePoint from doing a FormDigest check, just set the following piece of code in your WCF service:

var storeContext = HttpContext.Current;
HttpContext.Current = null;
// do your code
HttpContext.Current = storeContext;