Skip to main content

Weblog Ton Stegeman [MVP]

Go Search
Home
  

ODC 2008
If you have a question or suggestion, please contact me through Windows Live Messenger.
My status: .

If I am not online, please send me an e-mail.
Other Blogs
There are no items in this list.
Weblog Ton Stegeman [MVP] > Posts > SharePoint RPC part 2 - creating a subsite
SharePoint RPC part 2 - creating a subsite

In a previous article I showed how you can create MOSS publishing pages using SharePoint's FP-RPC. In this post I will describe how you can create a sub site using RPC. In this case we're using a combination of Frontpage RPC and WSS RPC. The first step is to create the site using RPC. After this, the site needs to be provisioned. In this step we will use WSS RPC to apply the site template.

I am running the sample code below in a WinForms application. In the UI I can enter the URL for the parent site, the new url of the sub site, and the name of the site template. The UI looks like this:

image

You will find the code in this zip file. This zip also contains the sample code for the first article about RPC.

Step 1 - Create the site (FP RPC)

In the code snippet below you will find the code to create the site. After initializing the variables, the rpcString is encoded (in GetRPCCall) before posting the RPC command using a WebClient.

private string CreateSite(string siteUrl, string parentUrl, string newUrl)
{
    string method = "create+service";
    string service = string.Format("/{0}/{1}", parentUrl, newUrl);
    string target = "_vti_bin/_vti_adm/admin.dll";
    string path = string.Format("{0}/{1}/", siteUrl, parentUrl);

    string rpcString = "method={0}&service_name={1}";

    // Get the RPC call data
    rpcString = String.Format(rpcString, method, service);
    byte[] callData = GetRPCCall(rpcString);
    string url = path + target;

    // Send the request.
    byte[] result = null;
    using (WebClient client = new WebClient())
    {
        client.Credentials = System.Net.CredentialCache.DefaultCredentials;
        client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
        client.Headers.Add("X-Vermeer-Content-Type", "application/x-www-form-urlencoded");
        result = client.UploadData(url, "POST", callData);
    }

    // Return the result.
    return System.Text.Encoding.UTF8.GetString(result);
}

After running this code succesfully, you will get a HTML response that looks like this (it just shows the first few lines):

<html>
<head>
    <title>vermeer RPC packet</title>
</head>
\n<body>\n<p>
    method=create service:12.0.0.6219\n<p>
        message=successfully created service '/News/Demo1'\n<p>
            service=\n<ul>
                \n<li>service_name=/News/Demo1\n<li>meta_info=\n<ul>
                    \n<li>vti_defaultlanguage\n<li>SW|en-us\n<li>vti_servercharsets\n<li>VX|windows-1257

When you navigate to your new site, it will look like this:

image

So we now have a site, but the template still needs to be applied.

Step 2 - Apply the template (WSS RPC)

First we initialize our variables and get a valid RequestDigest. This is a value that is used for security validation. The SharePoint object model contains a function to get a valid requestdigest for the Central Administration pages, but I didn't get it to work using that. Instead I request the parent site of our new site in code and extract the ID from the HTML that is returned by SharePoint.

string target = "_vti_bin/owssvr.dll";
string path = string.Format("{0}/{1}/{2}/", siteUrl, parentUrl, newUrl);
string rpcString = string.Empty;

// Get valid RequestDigest by getting the homepage of the parent site and parsing the HTML.
string digest = GetRequestDigest(siteUrl, parentUrl);

This digest string looks like this:
0x926E57EB23D64181BE56EA7C614FFDCD79206C697E290C588231A5359C6CA9975065D871616C185AC635A2BD5960D33B8EAFB00A3E7E8BDF279D365DBB31A5D8,17 Jul 2008 18:44:23 -0000

Here is the code to get a valid RequestDigest:

private string GetRequestDigest(string siteUrl, string parentUrl)
{
    string search = "id=\"__REQUESTDIGEST\"";
    string url = string.Format("{0}/{1}", siteUrl, parentUrl);

    using (WebClient client = new WebClient())
    {
        client.Credentials = System.Net.CredentialCache.DefaultCredentials;
        string digest = client.DownloadString(url);
        int p = digest.ToLower().IndexOf(search.ToLower());
        if (p > 0)
        {
            digest = digest.Substring(p+search.Length);
            digest = digest.Substring(digest.IndexOf("\"") + 1);
            digest = digest.Substring(0, digest.IndexOf("\""));
            return digest;
        }
    }
    return string.Empty;
}

I am not extremely happy about this implementation. If you have a better suggestion, please let me know.
If you do not pass a valid value to the WSS RPC call, your call will fail and you will get this WebException:

{"The remote server returned an error: (404) Not Found."}

Next thing to do is initialize the parameters for our RPC call, encode them and turn them into a byte array:

rpcString += string.Format("__REQUESTDIGEST={0}&", digest);
rpcString += "Cmd=DisplayPost&PostBody=";
rpcString += "<Method ID='Text'>";
rpcString +="<SetVar Name='Cmd'>SiteProvision</SetVar>";
rpcString +="<SetVar Name='CreateLists'>True</SetVar>";
rpcString += "<SetVar Name='SiteTemplate'>STS#0</SetVar>";
rpcString += string.Format("<SetVar Name='__REQUESTDIGEST'>{0}</SetVar>", digest);
rpcString += "</Method>";

// Get the RPC call data
byte[] callData = System.Text.Encoding.UTF8.GetBytes(rpcString);
byte[] data = new byte[callData.Length];
callData.CopyTo(data, 0);

Last thing to do is setup a new WebClient that will handle our request and return the result:

string url = path + target;

// Send the request.
byte[] result = null;
using (WebClient client = new WebClient())
{
    client.Credentials = System.Net.CredentialCache.DefaultCredentials;
    client.Headers.Add("Content-Type", "application/x-www-form-urlencoded");

    result = client.UploadData(url, "POST", data);
}

// Return the result.
return System.Text.Encoding.UTF8.GetString(result);

The result of our second step looks (if succesfull) like this:

<Result ID="Text" Code="0">
</Result>

And when we now navigate to the site, we will have a normal SharePoint site:

image

Click here to download the source code.

Comments

Fantastic post!

Great post Ton!

-iwkid
at 7/18/2008 8:23 AM

Just a small mistake in the source code

in the ProvisionSite()

the Template STS#0 is harcoded and should be replace by the argument "string template"
at 10/13/2009 3:02 AM

Add Comment

Items on this list require content approval. Your submission will not appear in public views until approved by someone with proper rights. More information on content approval.

Title


Body *


Your city *


Type the name of the city you live in (making it easier to handle spam...)

CurrentDate *

Select the current date (see if this gives me fewer spam...)
Attachments

 My Latest Blog Posts

SharePoint 2007 and Reporting ServicesUse SHIFT+ENTER to open the menu (new window).
SharePoint Objects – Insight in usage of your SharePoint artifactsUse SHIFT+ENTER to open the menu (new window).
SharePoint 2007 Custom list schema and the Content Query Web PartUse SHIFT+ENTER to open the menu (new window).
SharePoint 2010 Silverlight Client Object Model – ExecuteQuery vs ExecuteQueryAsyncUse SHIFT+ENTER to open the menu (new window).
SharePoint 2010, the Client Object Models and Bing MapsUse SHIFT+ENTER to open the menu (new window).
Having fun with SharePoint 2010, Silverlight 3 and Bing MapsUse SHIFT+ENTER to open the menu (new window).
Connecting TFS 2010 projects to SharePoint sitesUse SHIFT+ENTER to open the menu (new window).
Adding a database to the SharePoint database Server using SPDatabaseUse SHIFT+ENTER to open the menu (new window).
New version of Content by Type and filter web parts and a new family memberUse SHIFT+ENTER to open the menu (new window).
SharePoint 2010 Client Object Models – The ECMAScript libraryUse SHIFT+ENTER to open the menu (new window).
Slides and code of the DIWUG presentation of 29 september 2009Use SHIFT+ENTER to open the menu (new window).
Introducing SharePoint Security BlueprintsUse SHIFT+ENTER to open the menu (new window).
JQuery and SharePoint – Lookup fields and event listsUse SHIFT+ENTER to open the menu (new window).
SharePoint Filter web parts: using a context filter in a page layoutUse SHIFT+ENTER to open the menu (new window).
DevDays 2009: Ask the expertsUse SHIFT+ENTER to open the menu (new window).