从 Dynamic CRM Online 插件重命名 SharePoint Online 中的文件夹
Rename folder in SharePoint Online from Dynamic CRM Online Plugin
我在 Dynamics CRM Online 2015 中创建了一个插件,用于在 SharePoint Online 文档库中创建文件夹。该插件工作正常。但是,我想在 CRM 中的帐户名称更改时重命名文档库中的文件夹。
由于CRM和SharePoint都在线,我不能使用Microsoft.SharePoint.Client.dll所以我根据以下文章
使用了SPOAuthUtility Class
https://www.develop1.net/public/post/SharePoint-Integration-Reloaded-e28093-Part-3.aspx
创建文件夹的代码工作正常,我使用以下代码在 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 函数 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);
}
依次调用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 文件夹的代码
原来HTTP请求中SPOAuthUtility Class and HTTPHelper class that I had been using had been slightly modified to not include the Request Digest Header。没有请求摘要 Header,我仍然能够执行 GET 请求,但不能执行来自 Web 应用程序的 POST 请求。
这就是为什么代码在控制台应用程序中有效但在 CRM 插件(网络应用程序)中无效的原因,因为如 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.
可以从动态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 class
中的 SendODataJsonRequest 函数
我在 Dynamics CRM Online 2015 中创建了一个插件,用于在 SharePoint Online 文档库中创建文件夹。该插件工作正常。但是,我想在 CRM 中的帐户名称更改时重命名文档库中的文件夹。
由于CRM和SharePoint都在线,我不能使用Microsoft.SharePoint.Client.dll所以我根据以下文章
使用了SPOAuthUtility Classhttps://www.develop1.net/public/post/SharePoint-Integration-Reloaded-e28093-Part-3.aspx
创建文件夹的代码工作正常,我使用以下代码在 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 函数 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);
}
依次调用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 文件夹的代码
原来HTTP请求中SPOAuthUtility Class and HTTPHelper class that I had been using had been slightly modified to not include the Request Digest Header。没有请求摘要 Header,我仍然能够执行 GET 请求,但不能执行来自 Web 应用程序的 POST 请求。
这就是为什么代码在控制台应用程序中有效但在 CRM 插件(网络应用程序)中无效的原因,因为如 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.
可以从动态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 class
中的 SendODataJsonRequest 函数