Q:

Rename folder in SharePoint Online from Dynamic CRM Online Plugin

I have created a plugin in Dynamics CRM online 2015 that creates folders in a SharePoint Online Document Library. The plugin works fine. I want, however, to rename the folders in the Document Library when an Account's name in CRM changes.
Since both the CRM and SharePoint are online, I can't use Microsoft.SharePoint.Client.dll so I have used SPOAuthUtility Class based on the following articles
https://www.develop1.net/public/post/SharePoint-Integration-Reloaded-e28093-Part-3.aspx
http://www.wictorwilen.se/Post/How-to-do-active-authentication-to-Office-365-and-SharePoint-Online.aspx
https://bingsoft.wordpress.com/2013/06/19/crm-online-to-sharepoint-online-integration-using-rest-and-adfs/
The code for creating folders works fine and I use the following code to rename the folders upon the change of the Account name in CRM:
string restFolderQuery = "_api/web/getfolderbyserverrelativeurl('" + 
rootFolderName + "/" + oldName + "')/ListItemAllFields";

Uri url = new Uri(String.Format("{0}/{1}", webSiteUrl, restFolderQuery));

byte[] result = HTTPHelper.SendODataJsonRequest(
                 url,
                 "POST", // setting data to SP through the rest api usually uses the POST verb 
                 Encoding.UTF8.GetBytes("{ '__metadata':{ 'type': 'SP.Data.AccountItem' }, 
            'FileLeafRef': '" + newName + "' ,'Title:': '" + newName + "' }"),
                  (HttpWebRequest)HttpWebRequest.Create(url),
                 SpoAuthUtility.Current, // pass in the helper object that allows us to make authenticated calls to SPO rest services
                 new Dictionary<string, string>() {
                     {"IF-MATCH", "*"}, {"X-HTTP-Method", "MERGE" }
                  }
                 );

This will call the SendODataJsonRequest function in the HTTPHelper class:
public static byte[] SendODataJsonRequest(Uri uri, String method, byte[] requestContent, HttpWebRequest clientHandler, SpoAuthUtility authUtility, Dictionary<string, string> headers = null)
    {
        if (clientHandler.CookieContainer == null)
            clientHandler.CookieContainer = new CookieContainer();

        CookieContainer cookieContainer = authUtility.GetCookieContainer(); // get the auth cookies from SPO after authenticating with Microsoft Online Services STS

        foreach (Cookie c in cookieContainer.GetCookies(uri))
        {
            clientHandler.CookieContainer.Add(uri, c); // apppend SPO auth cookies to the request
        }
        // string digest = SpoAuthUtility.GetRequestDigest();

        Dictionary<string, string> _dic = new Dictionary<string, string>();
        _dic.Add("Authorization", "Bearer" + cookieContainer.GetCookieHeader(uri));
        return SendHttpRequest(
            uri,
            method,//digest,
            requestContent,
            "application/json;odata=verbose;charset=utf-8", // the http content type for the JSON flavor of SP REST services 
            clientHandler,
            _dic);
    }

Which in turn calls the SendHttpRequest function:
public static byte[] SendHttpRequest(Uri uri, String method, byte[] requestContent = null, string contentType = null, HttpWebRequest clientHandler = null, Dictionary<string, string> headers = null)
    {
        try
        {
            HttpWebRequest request = clientHandler == null ? (HttpWebRequest)HttpWebRequest.Create(uri) : clientHandler;

            byte[] responseStream;

            request.Method = method;
            request.Accept = contentType;
            request.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)"; // This must be here as you will receive 403 otherwise
            request.AllowAutoRedirect = false; // This is key, otherwise it will redirect to failed login SP page

            // append additional headers to the request
            if (headers != null)
            {
                foreach (var header in headers)
                {
                    if (request.Headers.AllKeys.Contains(header.Key))
                    {
                        request.Headers.Remove(header.Key);
                    }

                    request.Headers.Add(header.Key, header.Value);
                }
            }

            if (requestContent != null && (method == "POST" || method == "PUT" || method == "DELETE"))
            {
                if (!string.IsNullOrEmpty(contentType))
                {
                    request.ContentType = contentType; // if the request has a body set the MIME type
                }

                request.ContentLength = requestContent.Length;
                using (Stream s = request.GetRequestStream())
                {
                    s.Write(requestContent, 0, requestContent.Length);
                    s.Close();

                }
            }

            // Not using Using here as you may still like to access the reponse outside of this method
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8"));
            responseStream = Encoding.UTF8.GetBytes(sr.ReadToEnd());

            return responseStream;
        }
        catch (Exception ex)
        {

            throw;
        }
    }

The same code works fine in a Console App with the credentials provided and it does rename the specified folder, but it doesn't work in the CRM plugin
It seems like there is something wrong with the HTTPRequest this code creates since I get an error response from the server:
The remote server returned an error (400) bad request
Can anyone help me with the code to rename a SharePoint folder from a Dynamic CRM plugin

A:

It turned out that SPOAuthUtility Class and HTTPHelper class that I had been using had been slightly modified to not include the Request Digest Header in the HTTP Request. Without the Request Digest Header, I was still able to execute GET requests but not POST request from a web application.
That's why the code worked in a Console App but not in the CRM plugin (a web application), because as described in MSDN:

For reasons of security, by default, Microsoft SharePoint Foundation does not allow you to make posts from a Web application to modify the contents of the database unless you include security validation on the page making the request.

The modified function that can rename a SharePoint folder from a dynamics CRM plugin is as follow:
         spSite = new Uri(rootFolderForSharepoint);
        _spo = SpoAuthUtility.Create(spSite, sharepointUsername, WebUtility.HtmlEncode(sharepointPassword), false);
        string odataQuery = "_api/web/GetFolderByServerRelativeUrl('" + DocumentLibraryName + "/" + oldFolderUrl + "')/ListItemAllFields";

        byte[] content = ASCIIEncoding.ASCII.GetBytes(@"{ '__metadata':{ 'type': 'SP.Data.AccountItem' }, 'FileLeafRef': '" + newName + "' ,'Title:': '" + newName + "' }");

        string digest = _spo.GetRequestDigest();

        Uri url = new Uri(String.Format("{0}{1}", _spo.SiteUrl, odataQuery));

        // Set X-RequestDigest
        var webRequest = (HttpWebRequest)HttpWebRequest.Create(url);
        webRequest.Headers.Add("X-RequestDigest", digest);

        //Set additional Headers
        webRequest.Headers.Add("IF-MATCH", "*");
        webRequest.Headers.Add("X-HTTP-Method", "PATCH");

        // Send a json odata request to SPO rest services to fetch all list items for the list.
        byte[] result = HttpHelper.SendODataJsonRequest(
          url,
          "POST", // sending data to SP through the rest api usually uses the POST verb 
          content,
          webRequest,
          _spo // pass in the helper object that allows us to make authenticated calls to SPO rest services
          );

        string response = Encoding.UTF8.GetString(result, 0, result.Length);

        tracingservice.Trace("HTTP Response: {0}", response);

This will call the SendODataJsonRequest function in the HTTPHelper class

