Archive

Archive for September, 2009

Self Service Site Creation through code

September 9, 2009 12 comments

Note: This post only looks at SPSite.SelfServiceCreateSite from the object model.

The challenge

In most cases site collections are created by administrators with farm admin permissions, but in some cases you want to provide your users the ability to create site collections. Still a lot of developers use methods like the SPSite.Add() to create the site collections, which are actually meant for administrator task only and require you to have farm level permissions. Well, being a developer that is easily solved. Just add the web application pool account to the farm administrators and you can get the necessary permissions by simply using a SPSite.SelfServiceCreateSite method. Using this method you can allow regular users to create site collections, without giving them farm level permissions. To make this work there are two settings you must take into account: SPSecurity.RunWithElevatedPrivileges. Well, that’s something we DON’T want. Normal users should never get farm level permissions, simply because they always find a way to create havoc.

The solution

The solution is actually really simple. Microsoft provides us with the

  1. Enable Self-Service Site Management
    This allows the users to actually create site collections using the SPSite.SelfServiceCreateSite

               Figure 1: Enable Self-Service Site Management

  1. Have multiple managed paths
    Make sure you have another managed path as the (root) managed path. Sites should be created by default for most of the Web Applications, but you’ll need a managed path to be able to create new site collections.

               Figure 2: Create multiple managed paths

The implementation

For this example I created a WebPart which allows an user to create a new site collection. Within the code of the solution you’ll also find some other nice pieces of code, for example:

  • How to check if “Self-Service Site Management” is enabled
  • How to check if multiple managed paths are created
  • How to load the drop down list with the available managed paths (SPWebApplication.Prefixes)
  • How to load the drop down list with the available web templates (SPSite.GetWebTemplates(uint))
  • How to make use of SPLongOperation to show a nice progress window.

090909_2012_selfservice3

Figure 3: Example WebPart for the use of SelfServiceCreateSite

Once the information of the new site collection is entered and the user presses the Submit button, the site collection will be created. This might take a couple of seconds and during this time you don’t want to let the user click again on the submit button. The second time there might already be a site on the URL which is provided (since the user clicked on the button before), and they will get an exception. To prevent this problem, a progress screen is shown.

090909_2012_selfservice4

Figure 4: Creation of Site Collection is in progress

Once the site collection is created, the user will be redirected to the newly created site.

090909_2012_selfservice5

Figure 5: Newly generated Site Collection

The code

The following function shows the use of the SPSite.SelfServiceCreateSite. Basically it’s just calling the function with the correct variables, but there are a couple of pitfalls you should take into account

/// <summary>
/// This function will create a site collection using <see cref=”SPSite.SelfServiceCreateSite”/>
/// </summary>
/// <param name=”relativeSiteUrl”>
/// The relative url of a site. This should include a managed path since the root site
/// collection already exist. Example “sites/testsite”
/// </param>
/// <param name=”title”>The title of the new site</param>
/// <param name=”description”>The description of the new site</param>
/// <param name=”webTemplate”>The web template name</param>
/// <param name=”secondarySiteCollectionAdministratorLogin”>
/// The user login account of the secondary site collection administrator
/// </param>
/// <param name=”secondarySiteCollectionAdministratorName”>
/// The name of the secondary site collection administrator
/// </param>
/// <param name=”secondarySiteCollectionAdministratorEmail”>
/// The email address of the secondary site collection administrator
/// </param>
/// <returns>
/// The newly create <see cref=”SPSite”/> or null when an error has occured.
/// </returns>
private SPSite CreateNewSiteCollection(string relativeSiteUrl,
        string title,
        string description,

        string webTemplate,

        string secondarySiteCollectionAdministratorLogin,

        string secondarySiteCollectionAdministratorName,

        string secondarySiteCollectionAdministratorEmail)
{
    SPSite newSiteCollection = null;

    // The creation will only work if you set the primary administrator is set to the current user

    string primarySiteCollectionAdministratorLogin = SPContext.Current.Web.CurrentUser.LoginName;

    string primarySiteCollectionAdministratorName = SPContext.Current.Web.CurrentUser.Name;

    string primarySiteCollectionAdministratorEmail = SPContext.Current.Web.CurrentUser.Email;

    // Small change you want to set this variable on a different value as the root site collection

    uint localIdentifier = (uint)SPContext.Current.Web.Locale.LCID;
   
    try
   
{
        // Make sure we are at the root site collection

        using (SPSite rootSite = new SPSite(GetAuthorityUrl(SPContext.Current.Web.Url)))
       
{
            // If no secondary site collection administrator is provided, use null values

            // in stead of an empty string. Otherwise an Exception will be thrown.

            if (string.IsNullOrEmpty(secondarySiteCollectionAdministratorLogin))
               
newSiteCollection = rootSite.SelfServiceCreateSite(
                       
relativeSiteUrl,
                       
title,
                       
description,
                       
localIdentifier,
                       
webTemplate,
                       
primarySiteCollectionAdministratorLogin,
                       
primarySiteCollectionAdministratorName,
                       
primarySiteCollectionAdministratorEmail,
                       
null,
                       
null,
                       
null);
            else
           
{
                // When a secundary site collection has been provided, add this account as a

                // secundary site collection administrator
               
newSiteCollection = rootSite.SelfServiceCreateSite(
                       
relativeSiteUrl,
                       
title,
                       
description,
                       
localIdentifier,
                       
webTemplate,
                       
primarySiteCollectionAdministratorLogin,
                       
primarySiteCollectionAdministratorName,
                       
primarySiteCollectionAdministratorEmail,
                       
secondarySiteCollectionAdministratorLogin,
                       
secondarySiteCollectionAdministratorName,
                       
secondarySiteCollectionAdministratorEmail);
            }
        }
   
}
   
catch
   
{
        // You can implement some logging here. It can for example happen that you provide
        // a URL of a site that already exist, a template that not exist etc.
   
}

     return newSiteCollection;
}

The pitfalls

There are a couple of pitfalls you need to be aware of when you use SPSite.SelfServiceCreateSite. There are probably more, but these issues I encountered:

  1. Current user needs to be set as primary administrator
    SPSite.SelfServiceCreateSite will only work if you set the current user as the primary site administrator. When you want to allow users to create a site “on behalf” of somebody else, that is still possible. You’ll have to create the site with the current user as the primary site collection administrator and once it is created, change the owner (don’t forget, after making that change you might not be able to let the current user change other settings!).
  2. IntelliSense let you believe you have to add a secondary administrator
    When you use the
    SaveButton and use a custom control template for the list / content type.
    SPSite.SelfServiceCreateSite, IntelliSense tells you to provide string values for the secondary site collection administrator. By default my first instinct is to provide it with string.Empty (or perhaps “”). But this doesn’t work. You’ll get an error stating the user can’t be found or something like that. Instead you have to provide the function with null values.
  3. This will only work on POST actions
    SPSite.SelfServiceCreateSite will only allow you to create new site collections on POST actions. When you use the function on a GET action, you’ll get a nice security exception telling you not to do that. This means you can’t easily provide this functionality in an event receiver (they are triggered AFTER the post event). If you still want to use it in an event receiver one way to get this working is to create your own
  4. Not everybody may create site collections
    If you don’t want everybody to create site collections, you can prevent it by simply changing the permissions. By default the Site Permission to allow users to use Self-Service Site Creation is given to the Read role (so for all visitors!)
    090909_2012_selfservice6
  5. Users trying to create the site twice
    The operation to create a site collection might take a few seconds. This time will increase if you automatically want to activate features. An impatient user might want to “speed up” the process by clicking on the submit button again. This might cause the user to see a nice exception stating that the site is already created (he clicked the button twice, so he tries to create a site on the URL twice). To prevent this problem from occurring you might want to provide the user with a progress window. For this you can for example use the SPLongOperation

Download the code

Advertisements
Categories: Development, SharePoint

Using SPLongOperation

September 7, 2009 22 comments

The idea

Sometimes the actions triggered by users can take a while to process. This can for example happen when you create a site collection. At that time you:

  • Don’t want your users to continue clicking on the button, the action should finish first. With the example of the creation of a site collection, you don’t want two attempts of creating a site collection with the same URL.
  • Users must be made aware that the action might take a while and have the idea something is really happening behind the scenes.

 Microsoft provided some nice ways to have implement those long running operations. One is SPLongOperation which shows the user the “Operation in Progress” screen and it is actually pretty easy to implement.

The implementation

The implementation of the SPLongOperation is pretty easy. In a nutshell you create a new SPLongOperation, provide the different texts you want to display and you start your operation.

The next code example will be triggered by a button in a WebPart. It doesn’t actually do anything, but just let the current thread sleep for 5 seconds. In that time the “Operation in Progress” page is being displayed.

 /// <summary>
/// This test function will also call <see cref=”ALongRunningAction”/>, but it will
/// use <see cref=”SPLongOperation”/> to show a progress indication
/// </summary>
private void ALongActionWithProgressIndicator()
{
    // Determine the page to navigate to when the operation is successful
    string successUrl = SPContext.Current.Web.Url;

    // Create a new SPLongOperation
    SPLongOperation longOperation = new SPLongOperation(this.Page);

    // Provide the text displayed in bold
    longOperation.LeadingHTML = “Long running operation is being performed”;

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

    // Let’s start the code that takes a while from here
    longOperation.Begin();

    try
    {
        // The code that might take a while
       
Thread.Sleep(5000);

        //When the action is performed, the page will be redirect to this url
       longOperation.End(successUrl);
    }
    catch (ThreadAbortException)
    {
        // Don’t do anything, this error can occur because the SPLongOperation.End
        // performs a Response.Redirect internally and doesnt take into account
        // that other code might still be executed
    }
    catch (Exception ex)
    {
        // When an exception occurs, the page is redirected to the error page.
        // Redirection to another (custom) page is also possible
        SPUtility.TransferToErrorPage(ex.ToString());
    }
}
 

Pitfalls

There is one thing you might want to take into account when you use the SPLongOperation. The SPLongOperation.End internally uses a Response.Redirect which doesn’t take into account that you might have other code that is executed at the same time in a different thread. In order to prevent a ThreadAbortException message to display, you might want to catch that error.

The result

I created a small WebPart with two buttons for this demonstration.

  1. Button one doesn’t use the SPLongOperation and you’ll see the page loading for 5 seconds.
  2. Button two uses the SPLongOperation and it displays the “Operation in Progress” progress page

Figure 1: Test WebPart

Figure 2: Operation in Progress screen

Download the code

Categories: Development, SharePoint
Ben Prins

What I want to remember about SharePoint

blog.frederique.harmsze.nl

my world of work and user experiences

Bram de Jager - Coder, Speaker, Author

Office 365, SharePoint and Azure