从动态CRM Online插件重命名SharePoint Online中的文件夹

本文关键字:Online 文件夹 SharePoint 插件 动态 CRM 重命名 | 更新日期: 2023-09-27 18:26:28

我在Dynamics CRM online 2015中创建了一个插件,用于在SharePoint online文档库中创建文件夹。该插件运行良好。但是,当CRM中的帐户名称更改时,我希望重命名文档库中的文件夹。

由于CRM和SharePoint都是在线的,我不能使用Microsoft.SharePoint.Client.dll,所以我使用了基于以下文章的SPOAuthUtility类

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/

创建文件夹的代码运行良好,我使用以下代码在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" }
                  }
                 );

这将调用HTTPHelper类中的SendODataJsonRequest函数:

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);
    }

然后调用SendHttpRequest函数:

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;
        }
    }

相同的代码在具有凭据的控制台应用程序中运行良好,它确实重命名了指定的文件夹,但在CRM插件中不起作用

这段代码创建的HTTPRequest似乎有问题,因为我从服务器收到了错误响应:远程服务器返回错误(400)错误请求

有人能帮我从动态CRM插件重命名SharePoint文件夹的代码吗

从动态CRM Online插件重命名SharePoint Online中的文件夹

事实证明,我一直在使用的SPOAuthUtility类和HTTPHelper类经过了轻微修改,在HTTP请求中不包括请求摘要标头。如果没有RequestDigest Header,我仍然可以执行GET请求,但不能执行来自web应用程序的POST请求。

这就是为什么代码在控制台应用程序中有效,但在CRM插件(一个网络应用程序)中无效,因为如MSDN中所述:

出于安全考虑,默认情况下,Microsoft SharePoint Foundation不允许您通过Web应用程序发布以修改数据库的内容,除非您在提出请求的页面上包含安全验证。

修改后的功能可以从动态CRM插件重命名SharePoint文件夹,如下所示:

         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);

这将调用HTTPHelper类中的SendODataJsonRequest函数