【问题标题】:Create a folder in SP2013 using REST and HTTPClient使用 REST 和 HTTPClient 在 SP2013 中创建文件夹
【发布时间】:2014-08-20 22:21:43
【问题描述】:

我正在尝试使用 HTTPClient 和 REST 在 SP2013 中创建一个文件夹。

以下是对应用程序的要求和限制

  1. 我需要使用 REST 在 2013 文档库中创建一个文件夹。不允许 CSOM。

  2. 程序必须是 C# 控制台应用程序。

  3. 我必须仅使用 HTTPClient 来对 Web 服务进行所有调用。不应使用其他旧类或库。

  4. 集成身份验证是必须的。您不得在代码中输入您的用户名和密码。它必须使用进程的标识。

基于这些限制,我编写了这段代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Http.Formatting;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace RESTCreateFolder
{
    class Program
    {
        static void Main(string[] args)
        {
            Program p = new Program();
            int retVal = p.Process().Result;            
        }

        private async Task<int> Process()
        {
            string url = "http://bi.abhi.com/testweb/";
            using (HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }))
            {
                client.BaseAddress = new System.Uri(url);
                client.DefaultRequestHeaders.Add("Accept", "application/json; odata=verbose");
                string digest = await GetDigest(client);
                Console.WriteLine("Digest " + digest);
                try
                {
                    await CreateFolder(client, digest);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    Console.WriteLine(ex.StackTrace);
                }
            }
            return 0;
        }

        private object CreateRequest(string folderPath)
        {
            var type = new { type = "SP.Folder" };
            var request = new { __metadata = type, ServerRelativeUrl = folderPath };
            return request;
        }

        private async Task CreateFolder(HttpClient client, string digest)
        {
            client.DefaultRequestHeaders.Add("X-RequestDigest", digest);
            var request = CreateRequest("/test/foo");
            string json = JsonConvert.SerializeObject(request);
            StringContent strContent = new StringContent(json, System.Text.Encoding.UTF8, "application/json");
            strContent.Headers.ContentLength = json.Length;
            HttpResponseMessage response = await client.PostAsync("_api/web/folders", strContent);
            //response.EnsureSuccessStatusCode();
            if (response.IsSuccessStatusCode)
            {
                string content = await response.Content.ReadAsStringAsync();
                Console.WriteLine(content);
            }
            else
            {
                Console.WriteLine(response.StatusCode);
                Console.WriteLine(response.ReasonPhrase);
                string content = await response.Content.ReadAsStringAsync();
                Console.WriteLine(content);
            }
        }

        public async Task<string> GetDigest(HttpClient client)
        {
            string retVal = null;
            string cmd = "_api/contextinfo";                       
            HttpResponseMessage response = await client.PostAsJsonAsync(cmd, "");
            if (response.IsSuccessStatusCode)
            {
                string content = await response.Content.ReadAsStringAsync();
                JToken t = JToken.Parse(content);
                retVal = t["d"]["GetContextWebInformation"]["FormDigestValue"].ToString();
            }
            return retVal;
        }
    }
}

但是这段代码总是因为 BAD REQUEST 而失败。

您能否让“这个”代码工作并告诉我您是如何修复它的。我在 MSDN 上找到了很多文章,但它们都使用了我无法使用的 WebRequest 的旧方法。我必须使用 HttpClient。

编辑::

这是从提琴手捕获的原始请求

POST http://bi.abhi.com/testweb/_api/web/folders HTTP/1.1
Accept: application/json; odata=verbose
X-RequestDigest: 0x8B2A0904D5056E49DB886A72D59A86264A000F9AB14CE728407ECCD6F4369A7AD2585967BE9A57085344A5ACC99A4DA61D59E5EFA9A54B9B83564B2EA736F7F4,21 Aug 2014 20:24:15 -0000
Content-Type: application/json; charset=utf-8
Host: bi.abhi.com
Content-Length: 67
Expect: 100-continue

{"__metadata":{"type":"SP.Folder"},"ServerRelativeUrl":"/test/foo"}

这是提琴手的原始回复

HTTP/1.1 400 Bad Request
Cache-Control: private, max-age=0
Transfer-Encoding: chunked
Content-Type: application/json;odata=verbose;charset=utf-8
Expires: Wed, 06 Aug 2014 20:24:15 GMT
Last-Modified: Thu, 21 Aug 2014 20:24:15 GMT
Server: Microsoft-IIS/8.0
X-SharePointHealthScore: 0
SPClientServiceRequestDuration: 4
X-AspNet-Version: 4.0.30319
SPRequestGuid: a9c6b09c-9340-10e2-0000-093d0491623a
request-id: a9c6b09c-9340-10e2-0000-093d0491623a
X-RequestDigest: 0x8B2A0904D5056E49DB886A72D59A86264A000F9AB14CE728407ECCD6F4369A7AD2585967BE9A57085344A5ACC99A4DA61D59E5EFA9A54B9B83564B2EA736F7F4,21 Aug 2014 20:24:15 -0000
X-FRAME-OPTIONS: SAMEORIGIN
X-Powered-By: ASP.NET
MicrosoftSharePointTeamServices: 15.0.0.4569
X-Content-Type-Options: nosniff
X-MS-InvokeApp: 1; RequireReadOnly
Date: Thu, 21 Aug 2014 20:24:14 GMT

e6
{"error":{"code":"-1, System.InvalidOperationException","message":{"lang":"en-US","value":"The required version of WcfDataServices is missing. Please refer to http://go.microsoft.com/fwlink/?LinkId=321931 for more information."}}}
0

我已经完全修补了我的服务器环境,并且没有要应用的新更新。所以我不知道为什么它说缺少所需的 wcfdata 服务。

【问题讨论】:

  • SharePoint 在线还是本地?

标签: c# sharepoint-2013 dotnet-httpclient office365-apps officedev


【解决方案1】:

我解决了这个问题。使用了提供的答案

http://social.msdn.microsoft.com/Forums/en-US/a58a4bec-e936-48f9-b881-bc0a7ebb7f8a/create-a-folder-in-sp2013-document-library-using-rest-using-http-client?forum=appsforsharepoint

显然,在使用 StringContent 时,您必须将其设置为“application/json;odata=verbose”,否则会收到 400 错误请求。 StringContent 设置 Content-Type 标头。

StringContent strContent = new StringContent(json);
strContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;odata=verbose");

我的完整代码现在看起来像

class Program
{
    static void Main(string[] args)
    {
        Program p = new Program();
        int retVal = p.Process().Result;            
    }

    private async Task<int> Process()
    {
        string url = "http://bi.abhi.com/testweb/";
        using (HttpClient client = new HttpClient(new HttpClientHandler() { UseDefaultCredentials = true }))
        {
            client.BaseAddress = new System.Uri(url);
            client.DefaultRequestHeaders.Add("Accept", "application/json; odata=verbose");
            string digest = await GetDigest(client);
            Console.WriteLine("Digest " + digest);
            try
            {
                await CreateFolder(client, digest);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                Console.WriteLine(ex.StackTrace);
            }
        }
        return 0;
    }

    private object CreateRequest(string folderPath)
    {
        var type = new { type = "SP.Folder" };
        var request = new { __metadata = type, ServerRelativeUrl = folderPath };
        return request;
    }

    private async Task CreateFolder(HttpClient client, string digest)
    {
        client.DefaultRequestHeaders.Add("X-RequestDigest", digest);
        var request = CreateRequest("foo");
        string json = JsonConvert.SerializeObject(request);
        StringContent strContent = new StringContent(json);
        strContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json;odata=verbose");
        HttpResponseMessage response = await client.PostAsync("_api/web/getfolderbyserverrelativeurl('test/test123/')/folders", strContent);
        //response.EnsureSuccessStatusCode();
        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            Console.WriteLine(content);
        }
        else
        {
            Console.WriteLine(response.StatusCode);
            Console.WriteLine(response.ReasonPhrase);
            string content = await response.Content.ReadAsStringAsync();
            Console.WriteLine(content);
        }
    }

    public async Task<string> GetDigest(HttpClient client)
    {
        string retVal = null;
        string cmd = "_api/contextinfo";                       
        HttpResponseMessage response = await client.PostAsJsonAsync(cmd, "");
        if (response.IsSuccessStatusCode)
        {
            string content = await response.Content.ReadAsStringAsync();
            JToken t = JToken.Parse(content);
            retVal = t["d"]["GetContextWebInformation"]["FormDigestValue"].ToString();
        }
        return retVal;
    }
}

【讨论】:

    【解决方案2】:

    如果这是 SharePoint Online,这 4 个要求恐怕您无法做到。您需要在请求中发送 Authentication 标头或 cookie。 您可以添加 SP 客户端库,创建 SharepointOnlineClientCredentials,使用方法获取 cookie

    SharePointOnlineCredentials.GetAuthenticationCookie 
    

    并将 cookie 添加到 httpclient cookiecontainer。

    如果您在 SP On 本地,我认为它也不起作用,但您可以尝试将 NetworkCredentials 添加到 httpclient 请求中: HttpClient.GetAsync with network credentials 使用选项

    UseDefaultCredentials = true 
    

    正如已接受答案的评论中所说。但同样,我认为行不通。

    【讨论】:

    • 我已经在做“UseDefaultCredentials = true”了。我也能够正确获取摘要。所以凭据很好。但是当我尝试创建文件夹时会发生 BAD REQUEST。
    • 好的,抱歉。查看有关 REST 调用的链接。我认为您必须调用 Add 方法:msdn.microsoft.com/en-us/library/office/… 类似:/_api/web/folders/add('/Shared Documents/Folder A/Folder B')?@target=''跨度>
    • 您可能不需要 Target 查询字符串参数。另外,使用您的代码,我认为您快到了,但调用应该是: /_api/web/getfolderbyserverrelativeurl('/Shared Documents/Folder A')/folders('Folder B') 在之前使用 getfolderbyserverrelativeurl 方法/文件夹
    • 不起作用。错误是 {"error":{"code":"-2147024809, System.ArgumentException","message":{"lang":"en-US","value":"Value 不在预期范围内range."}}} 如果可能的话,你能把我上面的代码复制粘贴到 vs.net 中,并尝试让它在你的环境中工作吗?
    • 抱歉,我现在没有本地环境(使用 SP Online)。我的建议:使用 Google Chrome 打开您的 SP 站点,打开一个新选项卡并使用 Postman 插件,尝试 REST API URL 的一些变体,直到它工作。我很确定问题出在您使用的 URL 上,确保库在站点中,等等。
    猜你喜欢
    • 1970-01-01
    • 2013-04-30
    • 2019-08-11
    • 2021-07-02
    • 2015-06-07
    • 1970-01-01
    • 2014-05-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多