Harin Sandhoo's Blog

June 26, 2012

Using Windows Azure IaaS to host SharePoint 2010

Filed under: Azure, SharePoint — Harin @ 1:48 pm

This post is a follow-up to one I wrote awhile back, where we hosted SharePoint 2010 in a standalone VM Role (the Compute offering). That obviously was not supported / durable and was really just as a POC to see if it could be done.

Now that Microsoft has announced their Infrastructure as a Service (IaaS) offering (aka durable VM instances) and I’ve had some time to play with it, I thought it would be a good idea to share a powershell script I use to host SharePoint Farms in Microsoft’s Azure data centers in a way that will eventually be supported (once out of preview).

All this stuff is in preview, so proceed at your own risk.

I’ve created a sample powershell script after watching a great Tech Ed talk by Paul Stubbs. I don’t want to re-create good content for the sake of it, so I’ll just point you at his talk and give you the script to hopefully save you some time (since I couldn’t find his).

This script also assumes a lot of manual steps like rdp’ing into your domain controller box and running dcpromo, installing the SharePoint bits, configuring the SharePoint environment. It’s main purpose is to get you a physical environment where you can host SharePoint outside of your datacenter, so don’t expect to run it and have a fully configured SharePoint environment up and running.

The hands on labs are also good to get a feel of how to work with the powershell scripts.

Warning: The script sets up a lot of VMs (6 ->; 12 cores) and disks (14 ->; 6 OS disks, 7 100 GB data disks [for logs and data], and 1 15 GB data disk for the AD box). You will be charged for these, so make sure you delete the VMs, Disks, Virtual Network, services, once you are done.

In a production environment, you’ll likely want to add a redundant AD box, but it’s easy enough to do with the sample script.

I hope this saves you all some time.

Link to script: http://sdrv.ms/KBRxcf

Alt hosted on my company’s GitHub page:  https://github.com/AppliedIS/sp-azure-iaas

Advertisements

June 13, 2011

Integrating SharePoint and Mobile devices using Azure AppFabric Service Bus

Filed under: Azure, SharePoint — Harin @ 8:30 am

Although the WP7 for Azure toolkit has been released, I recently ran into an issue exposing SharePoint data to a WP7 app that I thought was worth sharing.  In this case, we have a SharePoint 2010 farm inside a corporate firewall, needing to expose data from the SharePoint User Profile Service to an application written on a WP7 mobile device.  To implement this, we created a Windows Service that hosts a webHttpRelayBinding endpoint so the WP7 application can make simple REST calls to get at the data.  By using a REST based endpoint, that also allowed us to write equivalent client applications for Android and iOS.  Going forward, the windows service can be brought in and managed in SharePoint using the Service Application model, but for a demo, simply installing the windows service on the SharePoint box was sufficient. 

High level architecture:

 

 

WCF Service Contract:

 For our service we have a service contract defined to as:

    [ServiceContract]
    public interface IProfileService
    {
        [OperationContract,
        WebGet(
            BodyStyle = WebMessageBodyStyle.Bare,
            ResponseFormat = WebMessageFormat.Xml,
            UriTemplate = "/FarmInfo")
        ]
        FarmInfo GetFarmInfo();

        [OperationContract, 
        WebGet(
            BodyStyle = WebMessageBodyStyle.Bare,
            ResponseFormat = WebMessageFormat.Xml,
            UriTemplate = "/Users?q={searchTerms}")
        ]
        UserList GetUsers(string searchTerms);

        [OperationContract, 
        WebGet(
            BodyStyle = WebMessageBodyStyle.Bare,
            ResponseFormat = WebMessageFormat.Xml,
            UriTemplate = "/Users/{userId}")
        ]
        Profile GetProfile(string userId);
    }
 

WCF Service Implementation:

I created a class called SPProfileReader which encapsulates the call to the SharePont UserProfileManager.  The service implementation looks something like this:

    public class ProfileService : IProfileService
    {
        private static object _synch = new object();
        private static SPProfileReader reader = null;

        private SPProfileReader Instance
        {
            get
            {
                return new SPProfileReader(System.Configuration.ConfigurationManager.AppSettings["SiteUrl"]);
            }
        }

        public FarmInfo GetFarmInfo()
        {
            FarmInfo retVal = null;
            try
            {
                retVal = new FarmInfo()
                {
                    id = "AIS Demos Farm",
                    url = "http://<demo farm url>",
                    centraladminurl = "<central admin url>",
                    description = "This farm is a demo environment meant to showcase Azure and SharePoint integration scenarios."
                };
            }
            catch (Exception e)
            {
                Trace.WriteLine(e.ToString());
            }
            return retVal;
        }

        public UserList GetUsers(string searchTerms)
        {
            UserList retVal = null;
            try
            {
                using (var rdr = Instance)
                {
                    retVal = rdr.GetUsers(searchTerms);
                }
            }
            catch (Exception e)
            {
                Trace.WriteLine(e.ToString());
            }
            return retVal;
        }

        public Profile GetProfile(string userId)
        {
            Profile retVal = null;
            try
            {
                using (var rdr = Instance)
                {
                    retVal = rdr.GetUserProfile(userId);
                }
            }
            catch (Exception e)
            {
                Trace.WriteLine(e.ToString());
            }
            return retVal;
        }
    }
 

Hosting the WCF Service:

Hosting the WCF Service is pretty straight forward and for completeness looks like this:

        public void StartHost()
        {
            try
            {
                //// Build the endpoint URI
                string serviceNamespace = System.Configuration.ConfigurationManager.AppSettings["SBNamespace"];
                string endPoint = System.Configuration.ConfigurationManager.AppSettings["SBEndpoint"];
                Uri address = ServiceBusEnvironment.CreateServiceUri("https", serviceNamespace, endPoint);

                //// Build the service bus credential
                string serviceUser = System.Configuration.ConfigurationManager.AppSettings["SBUser"];
                string serviceKey = System.Configuration.ConfigurationManager.AppSettings["SBKey"];
                TransportClientEndpointBehavior sharedSecretServiceBusCredential = new TransportClientEndpointBehavior();
                sharedSecretServiceBusCredential.CredentialType = TransportClientCredentialType.SharedSecret;
                sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerName = serviceUser;
                sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerSecret = serviceKey;

                Trace.WriteLine("Opening service bus connection: " + address.ToString());

                //// Create the wcf service host
                host = new WebServiceHost(typeof(ProfileService), address);

                //// Set the binding to WebHttpRelayBinding
                Microsoft.ServiceBus.WebHttpRelayBinding binding = new WebHttpRelayBinding();
                binding.Security.RelayClientAuthenticationType = RelayClientAuthenticationType.None;

                //// Create the endpoint
                ServiceEndpoint se = host.AddServiceEndpoint(typeof(IProfileService), binding, address);
                se.Behaviors.Add(sharedSecretServiceBusCredential);
                ServiceDebugBehavior sdb = host.Description.Behaviors.Find<ServiceDebugBehavior>();
                sdb.HttpHelpPageEnabled = false;

                //// Open host
                host.Open();
                Trace.WriteLine("Host open.");
            }
            catch(Exception e)
            {
                Trace.WriteLine("Exception occured while opening host:");
                Trace.WriteLine(e.ToString());
            }
        }

 

Sample WP7 Client Code:

Since the relay service is exposing the endpoint as via REST, integrating with mobile devices becomes trivial.  Note, if this is sensitive / production data, I would recommend utilizing the ACS to secure access to the endpoint (examples of how to do that can be seen in the Azure WP7 SDK).  Here is a bit of code showing how to access some data from the REST endpoint.

    public class ServiceProxy
    {
        private const string SBUri = "https://<myaccount>.servicebus.windows.net/SPProfileViewer/";

        public static void GetAllUsers(DownloadStringCompletedEventHandler callback)
        {
            WebClient client = new WebClient();
            string uri = string.Format("{0}Users",SBUri);
            client.DownloadStringCompleted += callback;
            client.DownloadStringAsync(new Uri(uri));
        }

        public static void SearchForUsers(string queryTerm, DownloadStringCompletedEventHandler callback)
        {
            WebClient client = new WebClient();
            string uri = string.Format("{0}Users?q={1}", SBUri, queryTerm);
            client.DownloadStringCompleted += callback;
            client.DownloadStringAsync(new Uri(uri));
        }

        public static void GetUserProfile(string userId, DownloadStringCompletedEventHandler callback)
        {
            WebClient client = new WebClient();
            string uri = string.Format("{0}Users/{1}", SBUri,userId);
            client.DownloadStringCompleted += callback;
            client.DownloadStringAsync(new Uri(uri), userId);
        }

        public static void GetFarmInfo(DownloadStringCompletedEventHandler callback)
        {
            WebClient client = new WebClient();
            string uri = string.Format("{0}FarmInfo", SBUri);
            client.DownloadStringCompleted += callback;
            client.DownloadStringAsync(new Uri(uri));
        }
    }
 

An Important ‘gotcha’ when working with SharePoint and the AppFabric Service Bus:

When hosting our relay service, we noticed that after a while the service host lost the connection to the Service Bus and our service was no longer accessible from the clients.  Working off and on with Microsoft Support for a few weeks, we finally tracked down what the issue was.  When the service creates a connection to the AppFabric Service Bus, it requests a security token.  Every ten minutes or so, the host attempts to renew that token.  The trouble comes in when you try and integrate in with SharePoint.  When you access the SPServiceContext and UserProfileManager and probably a bunch of other SharePoint API calls (as we did in this case), the ServicePointManager.ServerCertificateValidationCallback delegate is changed so that it only trusts the certificates that SharePoint knows about.  Unfortunately, the GTE CyberTrust Root certificate that ultimately signed our Service Bus certificate is not trusted by SharePoint.  If you are experiencing this problem, you may notice errors in your WCF / System.NET trace log such as:

System.Net Error: 0 : [6256] Exception in the HttpWebRequest#3038911:: – The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

System.Net Error: 0 : [6256] Exception in the HttpWebRequest#3038911::EndGetRequestStream – The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel.

 

The work around is as follows (these are from Mog Liang from Microsoft’s support team):

  1. Download the ACS server certificate’s root CA ‘GTE CyberTrust Global Root’ by accessing ACS service ‘https://<myaccount&gt;.accesscontrol.windows.net/WRAPv0.9/
  2. Open ‘SharePoint 2010 Central Administration’ tool
  3. Open ‘Security -> Manage Trust’ page  
  4. Click ‘new’ button, in popup page, input the ‘GTE CyberTrust Global Root’ certificate, give a name, and click OK

 

November 19, 2009

Using the Service Management APIs to Automate Azure Deployments

Filed under: Azure — Harin @ 11:27 am

With the latest CTP, Microsoft announced the a ServiceManagement API that can be used to automate builds (at least to your staging environment).  Note:  Screenshots are coming soon.

Here’s a simple walkthrough on how to create a certificate for use with the Azure Service Management APIs.

Create a self signed certificate

  1. Open IIS 7
  2. Features -> Server Certificates
  3. Create Self-Signed Certificate
  4. Enter a friendly name and click ok.
  5. Export the certificate
    1. Start Certificate Manager by clicking on Start -> Run, and entering certmgr.msc
    2. Find your certificate (Mine was located in ‘Trusted Root Certification Authorities’
    3. Export the certificate

i.      Right click on -> All Tasks -> Export, click next after the welcome screen.

ii.      Do not export the private key, and click next.

iii.      Select DER encoded binary X.509 (.CER)

iv.      Select a file location

v.      Click on Finish

Associate the certificate with Azure

  1. Go to the https://windows.azure.com portal and sign in with your account credentials
  2. Navigate to the Account Tab a nd click on ‘Manage My API Certificates’
  3. Click on Browse, select the certificate that was exported previously, and then click upload.
  4. The certificate should appear in the Installed Certificates list
  5. Start using the Management Service API.
    1. Here is sample code from MSDN
HttpWebRequest CreateHttpRequest(Uri uri, string httpMethod, X509Certificate2 accessCertificate, TimeSpan timeout)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Timeout = (int)timeout.TotalMilliseconds;
request.ReadWriteTimeout = (int)timeout.TotalMilliseconds * 100;
request.Method = httpMethod;
request.ClientCertificates.Add(accessCertificate);
request.Headers.Add(Constants.VersionHeader, Constants.VersionTarget);
request.ContentType = Constants.ContentTypeXml;
return request;
}

Note:  If you are calling this code from a machine where the certificate was not originally generated, then you may need to export the certificate with the private key and install it on that server.  For example, if you are automating builds using TFS, then export the certificate with the private key, and import it on the build server.

To automate deployments with TFS the general steps are:

  1. Create and associate a management certificate as outlined above.
  2. Make sure the build server has the certificate installed with the private key.
  3. Create a build for your Azure solution in TFS.
  4. Run cspack.exe to package your deployment package on the build output to package the deployment.
  5. Use the BlobStorage REST APIs / provided StorageClient to upload the package into blob storage.
private static string SendFileToContainer(BlobContainer deploymentContainer, string filePath, string versionName)
{
string retVal = string.Empty;
FileInfo info = new FileInfo(filePath);
string newFileName = DateTime.Now.ToString("yyyyMMddHHmmss") + "_" + versionName + "_" + info.Name;
BlobProperties blobProp = new BlobProperties(newFileName);
blobProp.Metadata = new System.Collections.Specialized.NameValueCollection();
blobProp.Metadata.Add("version", versionName);
if (deploymentContainer.CreateBlob(blobProp, new BlobContents(File.ReadAllBytes(filePath)), true))
{
retVal = deploymentContainer.ContainerUri.AbsoluteUri + "/" + newFileName;
}
return retVal;
}

Finally, use the ServiceManagement REST APIs to perform the deployment.  Here’s some more code that may help.

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
//using AIS.Azure.ServiceManagementWrapper.Constants;
//using AIS.Azure.ServiceManagementWrapper.HelperObjects;
using System.Security.Cryptography.X509Certificates;
namespace AIS.Azure.ServiceManagementWrapper
{
namespace HelperObjects
{
public class HostedService
{
public class HostedServiceProperties
{
public HostedServiceProperties() { }
public string Description { get; set; }
public string AffinityGroup { get; set; }
public string Location { get; set; }
public string Label { get; set; }
}

public class HostedServiceDeploymentRoleInstance
{
public string RoleName { get; set; }
public string InstanceName { get; set; }
public string InstanceStatus { get; set; }
}

public class HostedServiceDeployment
{
public string Name { get; set; }
public string DeploymentSlot { get; set; }
public string PrivateID { get; set; }
public string Status { get; set; }
public string Label { get; set; }
public string Url { get; set; }
public string Configuration { get; set; }
public IEnumerable<HostedServiceDeploymentRoleInstance> RoleInstances { get; set; }
public string UpgradeDomainCount { get; set; }
}
public HostedService() { }

public string Url { get; set; }
public string ServiceName { get; set; }
public HostedServiceProperties Properties { get; set; }
public IEnumerable<HostedServiceDeployment> Deployments { get; set; }

public override string ToString()
{
StringBuilder blder = new StringBuilder();
blder.AppendLine("ServiceName: " + ServiceName);
blder.AppendLine("Url: " + Url);
blder.AppendLine("Description: " + Properties.Description);
blder.AppendLine("AffinityGroup: " + Properties.AffinityGroup);
blder.AppendLine("Location: " + Properties.Location);
blder.AppendLine("Label: " + Properties.Label);
blder.AppendLine("Deployments:");
foreach (var deployment in Deployments)
{
blder.AppendLine("Deployment:");
blder.AppendLine("Name:\t\t" + deployment.Name);
blder.AppendLine("DeploymentSlot:\t" + deployment.DeploymentSlot);
blder.AppendLine("PrivateID:\t" + deployment.PrivateID);
blder.AppendLine("Status:\t\t" + deployment.Status);
blder.AppendLine("Label:\t\t" + deployment.Label);
blder.AppendLine("\t\tUrl:\t\t" + deployment.Url);
blder.AppendLine("Configuration:\t" + deployment.Configuration);
blder.AppendLine("UpgradeDomainCount:\t" + deployment.UpgradeDomainCount);
foreach (var roleinstance in deployment.RoleInstances)
{
blder.AppendLine("RoleInstance:");
blder.AppendLine("RoleName:\t" + roleinstance.RoleName);
blder.AppendLine("InstanceName:\t" + roleinstance.InstanceName);
blder.AppendLine("InstanceStatus:\t" + roleinstance.InstanceStatus);
}
}
return blder.ToString();
}

}

namespace Constants
{

class RequestTypes
{
public const string GET = "GET";
public const string POST = "POST";
public const string DELETE = "DELETE";
public const string LIST = "LIST";
}

class Headers
{
public const string x_ms_version_header = "x-ms-version";
public const string x_ms_version_value = "2009-10-01";
public const string x_ms_request_id_header = "x-ms-request-id";
}

class ContentTypes
{
public const string XML = "xml";
}

class HostedServices
{
public const string Namespace = "http://schemas.microsoft.com/windowsazure";
public const string ListHostedServices = "https://management.core.windows.net/{0}/services/hostedservices";
public const string GetHostedServiceProperties = "https://management.core.windows.net/{0}/services/hostedservices/{1}?embed-detail={2}";
public const string UpgradeDeploymentByDeploymentSlot = "https://management.core.windows.net/{0}/services/hostedservices/{1}/deploymentslots/{2}/?comp=upgrade";
public const string UpgradeDeploymentByDeploymentName = "https://management.core.windows.net/{0}/services/hostedservices/{1}/deployments/{2}/?comp=upgrade";
}
}

class ServiceManager
{
public enum DeploymentSlots { Staging, Production};
public enum Mode {Auto, Manual};
private static XNamespace ns = "http://schemas.microsoft.com/windowsazure";

private ServiceManager()
{
}

private static HttpWebRequest CreateHttpRequest(string requestUri, string httpMethod, X509Certificate accessCertificate, TimeSpan timeout)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUri);
request.Timeout = (int)timeout.TotalMilliseconds;
request.ReadWriteTimeout = (int)timeout.TotalMilliseconds * 100;
request.Method = httpMethod;
request.ClientCertificates.Add(accessCertificate);
request.Headers.Add(Constants.Headers.x_ms_version_header,
Constants.Headers.x_ms_version_value);
request.ContentType = Constants.ContentTypes.XML;
return request;
}

private static string ValueOrEmpty(XElement element)
{
return (element != null) ? element.Value : string.Empty;
}

private static XElement ProcessResponse(HttpWebRequest request)
{
XElement retVal = null;
using (WebResponse resp = request.GetResponse())
{
using (StreamReader respStream = new StreamReader(resp.GetResponseStream()))
{
string responseText = respStream.ReadToEnd();
retVal = XDocument.Parse(responseText).Root;
}
}
return retVal;
}

/// <summary>
///
/// </summary>
/// <param name="subscriptionId"></param>
/// <param name="certificatePath"></param>
/// <param name="msTimeout"></param>
/// <returns></returns>
public static IEnumerable<HostedService> ListHostedServices(string subscriptionId, string certificatePath, double msTimeout)
{
string strUrl = string.Format(Constants.HostedServices.ListHostedServices, subscriptionId);

X509Certificate2 cert = new X509Certificate2(certificatePath);

HttpWebRequest req = CreateHttpRequest(strUrl, RequestTypes.GET, cert, TimeSpan.FromMilliseconds(msTimeout));

var response = ProcessResponse(req);

var serviceList = from svc in response.Descendants(ns + "HostedService")
select new { Url = svc.Element(ns + "Url").Value, ServiceName = svc.Element(ns + "ServiceName").Value };

IEnumerable<HostedService> retVal = new List<HostedService>();
// Populate the service by just getting the values
foreach (var service in serviceList)
{
retVal = retVal.Concat<HostedService>(GetHostedServiceProperties(subscriptionId, service.ServiceName, true, certificatePath, msTimeout));
}
return retVal;
}
/// <summary>
///
/// </summary>
/// <param name="subscriptionId"></param>
/// <param name="serviceName"></param>
/// <param name="embedDetail"></param>
/// <param name="certificatePath"></param>
/// <param name="msTimeout"></param>
/// <returns></returns>
public static IEnumerable<HostedService> GetHostedServiceProperties(string subscriptionId, string serviceName, bool embedDetail, string certificatePath, double msTimeout)
{
string strUrl = string.Format(Constants.HostedServices.GetHostedServiceProperties, subscriptionId, serviceName, embedDetail.ToString().ToLower());

X509Certificate2 cert = new X509Certificate2(certificatePath);

HttpWebRequest req = CreateHttpRequest(strUrl, RequestTypes.GET, cert, TimeSpan.FromMilliseconds(msTimeout));

XElement response = ProcessResponse(req);

var serviceList = from svc in response.DescendantsAndSelf(ns + "HostedService")
select new HostedService()
{
Url = svc.Element(ns + "Url").Value,
ServiceName = svc.Element(ns + "ServiceName").Value,
Properties = new HostedService.HostedServiceProperties()
{
Description = ValueOrEmpty(svc.Element(ns + "HostedServiceProperties").Element(ns + "Description")),
AffinityGroup = ValueOrEmpty(svc.Element(ns + "HostedServiceProperties").Element(ns + "AffinityGroup")),
Location = ValueOrEmpty(svc.Element(ns + "HostedServiceProperties").Element(ns + "Location")),
Label = ValueOrEmpty(svc.Element(ns + "HostedServiceProperties").Element(ns + "Label"))
},
Deployments = from deployment in svc.Element(ns + "Deployments").Elements(ns + "Deployment")
select new HelperObjects.HostedService.HostedServiceDeployment()
{
Name = ValueOrEmpty(deployment.Element(ns + "Name")),
DeploymentSlot = ValueOrEmpty(deployment.Element(ns + "DeploymentSlot")),
PrivateID = ValueOrEmpty(deployment.Element(ns + "PrivateID")),
Status = ValueOrEmpty(deployment.Element(ns + "Status")),
Label = ValueOrEmpty(deployment.Element(ns + "Label")),
Url = ValueOrEmpty(deployment.Element(ns + "Url")),
Configuration = ValueOrEmpty(deployment.Element(ns + "Configuration")),
RoleInstances = from roleinstance in deployment.Element(ns + "RoleInstanceList").Elements(ns + "RoleInstance")
select new HelperObjects.HostedService.HostedServiceDeploymentRoleInstance()
{
RoleName = ValueOrEmpty(roleinstance.Element(ns + "RoleName")),
InstanceName = ValueOrEmpty(roleinstance.Element(ns + "InstanceName")),
InstanceStatus = ValueOrEmpty(roleinstance.Element(ns + "InstanceStatus"))
},
UpgradeDomainCount = ValueOrEmpty(deployment.Element(ns + "UpgradeDomainCount"))
}
};
return serviceList;
}
/// <summary>
///
/// </summary>
/// <param name="subscriptionId"></param>
/// <param name="serviceName"></param>
/// <param name="deploymentSlot"></param>
/// <param name="mode"></param>
/// <param name="packageUrl"></param>
/// <param name="configuration"></param>
/// <param name="label"></param>
/// <param name="roleNameToUpgrade">Optional.  Pass null or String.Empty if none.</param>
/// <param name="certificatePath"></param>
/// <param name="msTimeout"></param>
/// <returns></returns>
public static string UpgradeDeploymentByDeploymentSlot(string subscriptionId,
string serviceName,
DeploymentSlots deploymentSlot,
Mode mode,
string packageUrl,
string configuration,
string label,
string roleNameToUpgrade,
string certificatePath,
double msTimeout)
{

string strUrl = string.Format(Constants.HostedServices.UpgradeDeploymentByDeploymentSlot, subscriptionId, serviceName, Enum.GetName(typeof(DeploymentSlots),deploymentSlot).ToLower());

X509Certificate2 cert = new X509Certificate2(certificatePath);

HttpWebRequest req = CreateHttpRequest(strUrl, RequestTypes.POST, cert, TimeSpan.FromMilliseconds(msTimeout));
using (XmlTextWriter requestBodyStream = new XmlTextWriter(req.GetRequestStream(), Encoding.UTF8))
{
//requestBodyStream.Write();
XNamespace azureNS = (string)Constants.HostedServices.Namespace.Clone();
XDocument doc = new XDocument(
new XDeclaration("1.0","utf-8", "yes"),
new XElement( azureNS + "UpgradeDeployment",
new XElement(azureNS + "Mode", Enum.GetName(typeof(Mode), mode).ToLower()),
new XElement(azureNS + "PackageUrl", packageUrl),
new XElement(azureNS + "Configuration", configuration),
new XElement(azureNS + "Label", Convert.ToBase64String( Encoding.UTF8.GetBytes(label)))
));

if (!string.IsNullOrEmpty(roleNameToUpgrade))
{
doc.Root.Element(azureNS + "Label").AddAfterSelf(new XElement(azureNS + "RoleToUpgrade", roleNameToUpgrade));
}

doc.Save(requestBodyStream);
}
req.ContentType = "application/xml";

string retVal = string.Empty;
using (WebResponse response = req.GetResponse())
{
try
{
retVal = response.Headers[Constants.Headers.x_ms_request_id_header];
}
catch(NullReferenceException ex)
{
// The request header was not found
retVal = string.Empty;
}
}

return retVal;
}

}
}

Create a free website or blog at WordPress.com.