Upload a wsp file to Office 365 (SP 2013) using WebClient

In recent project I need to create a script to apply a design package to site collections in SharePoint Online. The first thing I need to do is to upload the design package (wsp file) to a document library. There is Client API to upload the file to SharePoint but there is size limitation, so I decided to use WebClient  PUT method instead. There are some catches that I found when using this approach:

  • I couldn’t just set the WebClient.Credentials to SharePoint Online Credentials as I would get 403 error. Solution: I need to send the SharePoint security token back as a FedAuth cookie, as a result I need to have a custom WebClient that has Cookie Container
  • I was getting ServerException (Unable to read cabinet info from) when run the Client API DesignPackage.Install on the uploaded wsp file. And I found that the WebClient.UploadFile method somehow didn’t maintain the file format properly. Solution: I need to use the OpenWrite method and upload it in a stream

Below is the working code. First I created a custom web client that accepts Cookie. There is other benefit of using this approach as we have more control on the web request object such as we can increase the timeout as well.

    class SPWebClient : WebClient
    {
        public CookieContainer CookieContainer { get; set; }

        protected override WebRequest GetWebRequest(Uri address)
        {
            HttpWebRequest request = base.GetWebRequest(address) as HttpWebRequest;
            if (request != null)
            {
                request.CookieContainer = CookieContainer;
            }
            return request;
        }
    }

Below is the upload routine. the site Url is the siteUrl in Office 365, the file Url is the document library url such as “SiteAssets/MyDesignPackage.wsp”, local path is the location of the wsp file in the filesystem.

As I mentioned above that I need to have claim base authentication cookie (“FedAuth”) and set its value as the security token found in the SPOIDCRL. And lastly upload the file in a stream (DON’T use UploadFile method!)

   private static void UploadFile(string siteUrl ,string fileUrl, string localPath, SharePointOnlineCredentials credentials)
        {
            var targetSite = new Uri(siteUrl);

            using (var spWebClient = new SPWebClient())
            {
                var authCookie = credentials.GetAuthenticationCookie(targetSite);
                spWebClient.CookieContainer = new CookieContainer();
                spWebClient.CookieContainer.Add(new Cookie("FedAuth",
                          authCookie.Replace("SPOIDCRL=", string.Empty),
                          string.Empty, targetSite.Authority));
                spWebClient.UseDefaultCredentials = false;
                try
                {
                    Stream stream = spWebClient.OpenWrite(targetSite + fileUrl, "PUT");
                    BinaryWriter writer = new BinaryWriter(stream);
                    writer.Write(IO.File.ReadAllBytes(localPath));
                    writer.Close();
                    stream.Close();
                }
                catch (WebException we)
                {
                    Console.WriteLine(we.Message);
                }
                Console.WriteLine("done");
            }
        }

In the next post I will show you how to use the DesignPackage CSOM to install and apply the Design Package.