最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - SharePoint REST API - HttpClient - Stack Overflow

programmeradmin0浏览0评论

In my SharePointREST Service I can make a call to add a folder to a library as follows:

public async Task<string> AddFolderAsync(string library, string folderName)
{
      var _serverRelativeUrl = string.Join("/", new string[] { library, folderName });
      var _type = "SP.Folder";
      var kvPropertyValues = new List<KeyValuePair<string, string>>
      {
          new KeyValuePair<string, string>(ServerRelativeUrl, _serverRelativeUrl)
      };

      string json = GetJsonMetadataStringByType(_type, kvPropertyValues);
      // this returns: '{'__metadata': {'type': 'SP.Folder'},'ServerRelativeUrl':'TEST/<folderName>'}'
      const string urlTemplate = "{0}/_api/web/folders";
      var restUrl = string.Format(urlTemplate, webUrl);
                                        
      var endpoint = _authenticationManager.GetWebRequest(restUrl, HttpMethod.Post, null, false);

      using Stream requestStream = endpoint.GetRequestStream();
      using StreamWriter writer = new(requestStream);
      {
            writer.Write(json);
            writer.Flush();
      }
            
       HttpWebResponse httpResponse = await GetResponse(endpoint);

       // Further stuff to be done here...
}

FYI, the json value looks like this when inserted:

{'__metadata': {'type': 'SP.Folder'},'ServerRelativeUrl':'TEST/<folderName>'}

This is in alignment with the instructions found here: Learn Microsoft - SharePoint REST API

This works brilliant, the GetWebRequest call populates the headers and returns the request, this works all good. The webrequest method looks like this:

public HttpWebRequest GetWebRequest(string url, HttpMethod method, string xHttpMethod, bool noMetaData)
{
      try
      {
            var accessToken = EnsureAccessTokenAsync(siteURI, user, password).GetAwaiter().GetResult();
            var odata = noMetaData ? OData.NOMETADATA : OData.VERBOSE;
            var endpointRequest = HttpWebRequest.CreateHttp(url);
            endpointRequest.Method = method.ToString();

            endpointRequest.Accept = $"application/json;odata={odata}";
            endpointRequest.ContentType = $"application/json;odata={odata}";
            endpointRequest.Headers.Add("Authorization", "Bearer " + accessToken);

            if (!string.IsNullOrEmpty(xHttpMethod))
            {
                  endpointRequest.Headers.Add("IF-MATCH", "*");
                  endpointRequest.Headers.Add("X-HTTP-Method", xHttpMethod.ToUpper());
            }

            return endpointRequest;
       }
       catch (System.Exception)
       {

            throw;
       }
}

But when I try to do this same call via a HttpClient call I get an "Bad Request" return?

i.e.

var sc = new StringContent(json, Encoding.UTF8, MediaTypeNames.Application.Json);
var _httpResponse = await _authenticationManager.GetHttpResponseFromRequestWithBody(restUrl, HttpMethod.Post, sc, null);

I collect the HttpResponseMessage via below two methods:

private HttpRequestMessage GetHttpRequestMessage(string url, HttpMethod method, string xHttpMethod, string odata)
{
    var request = new HttpRequestMessage(method, url);

    // Set Bearer accessToken
    var accessToken = EnsureAccessTokenAsync(siteURI, user, password).GetAwaiter().GetResult();
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

    // Set AcceptHeader
    var acceptHeader = MediaTypeWithQualityHeaderValue.Parse($"application/json;odata={odata}");
    request.Headers.Accept.Add(acceptHeader);

    // IF-Match header
    if (!string.IsNullOrEmpty(xHttpMethod))
    {
        // request.Headers.Add("IF-MATCH", "*");
        request.Headers.IfMatch.Add(new EntityTagHeaderValue("*"));
        request.Headers.Add("X-HTTP-Method", xHttpMethod.ToUpper());
    }

    return request;
}

public Task<HttpResponseMessage> GetHttpResponseFromRequestWithBody(string url, HttpMethod method, HttpContent content, string xHttpMethod, string odata = OData.NOMETADATA)
{
    var request = GetHttpRequestMessage(url, method, xHttpMethod, odata);
    request.Content = content;
    Debug.WriteLine(request.Content);

    return httpClient.SendAsync(request);
}

This works v=for every call where I need to 'GET' information, but not for the 'UPDATE/PUT' or 'POST' calls for some reason?

If I do that the response comes back as a "Bad Request" despite the fact that it is -as far as I can determine- an identical call?

Can anyone help out here?

In my SharePointREST Service I can make a call to add a folder to a library as follows:

public async Task<string> AddFolderAsync(string library, string folderName)
{
      var _serverRelativeUrl = string.Join("/", new string[] { library, folderName });
      var _type = "SP.Folder";
      var kvPropertyValues = new List<KeyValuePair<string, string>>
      {
          new KeyValuePair<string, string>(ServerRelativeUrl, _serverRelativeUrl)
      };

      string json = GetJsonMetadataStringByType(_type, kvPropertyValues);
      // this returns: '{'__metadata': {'type': 'SP.Folder'},'ServerRelativeUrl':'TEST/<folderName>'}'
      const string urlTemplate = "{0}/_api/web/folders";
      var restUrl = string.Format(urlTemplate, webUrl);
                                        
      var endpoint = _authenticationManager.GetWebRequest(restUrl, HttpMethod.Post, null, false);

      using Stream requestStream = endpoint.GetRequestStream();
      using StreamWriter writer = new(requestStream);
      {
            writer.Write(json);
            writer.Flush();
      }
            
       HttpWebResponse httpResponse = await GetResponse(endpoint);

       // Further stuff to be done here...
}

FYI, the json value looks like this when inserted:

{'__metadata': {'type': 'SP.Folder'},'ServerRelativeUrl':'TEST/<folderName>'}

This is in alignment with the instructions found here: Learn Microsoft - SharePoint REST API

This works brilliant, the GetWebRequest call populates the headers and returns the request, this works all good. The webrequest method looks like this:

public HttpWebRequest GetWebRequest(string url, HttpMethod method, string xHttpMethod, bool noMetaData)
{
      try
      {
            var accessToken = EnsureAccessTokenAsync(siteURI, user, password).GetAwaiter().GetResult();
            var odata = noMetaData ? OData.NOMETADATA : OData.VERBOSE;
            var endpointRequest = HttpWebRequest.CreateHttp(url);
            endpointRequest.Method = method.ToString();

            endpointRequest.Accept = $"application/json;odata={odata}";
            endpointRequest.ContentType = $"application/json;odata={odata}";
            endpointRequest.Headers.Add("Authorization", "Bearer " + accessToken);

            if (!string.IsNullOrEmpty(xHttpMethod))
            {
                  endpointRequest.Headers.Add("IF-MATCH", "*");
                  endpointRequest.Headers.Add("X-HTTP-Method", xHttpMethod.ToUpper());
            }

            return endpointRequest;
       }
       catch (System.Exception)
       {

            throw;
       }
}

But when I try to do this same call via a HttpClient call I get an "Bad Request" return?

i.e.

var sc = new StringContent(json, Encoding.UTF8, MediaTypeNames.Application.Json);
var _httpResponse = await _authenticationManager.GetHttpResponseFromRequestWithBody(restUrl, HttpMethod.Post, sc, null);

I collect the HttpResponseMessage via below two methods:

private HttpRequestMessage GetHttpRequestMessage(string url, HttpMethod method, string xHttpMethod, string odata)
{
    var request = new HttpRequestMessage(method, url);

    // Set Bearer accessToken
    var accessToken = EnsureAccessTokenAsync(siteURI, user, password).GetAwaiter().GetResult();
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

    // Set AcceptHeader
    var acceptHeader = MediaTypeWithQualityHeaderValue.Parse($"application/json;odata={odata}");
    request.Headers.Accept.Add(acceptHeader);

    // IF-Match header
    if (!string.IsNullOrEmpty(xHttpMethod))
    {
        // request.Headers.Add("IF-MATCH", "*");
        request.Headers.IfMatch.Add(new EntityTagHeaderValue("*"));
        request.Headers.Add("X-HTTP-Method", xHttpMethod.ToUpper());
    }

    return request;
}

public Task<HttpResponseMessage> GetHttpResponseFromRequestWithBody(string url, HttpMethod method, HttpContent content, string xHttpMethod, string odata = OData.NOMETADATA)
{
    var request = GetHttpRequestMessage(url, method, xHttpMethod, odata);
    request.Content = content;
    Debug.WriteLine(request.Content);

    return httpClient.SendAsync(request);
}

This works v=for every call where I need to 'GET' information, but not for the 'UPDATE/PUT' or 'POST' calls for some reason?

If I do that the response comes back as a "Bad Request" despite the fact that it is -as far as I can determine- an identical call?

Can anyone help out here?

Share Improve this question asked Feb 4 at 7:34 mtholenmtholen 1,6932 gold badges15 silver badges27 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 2

As is very often the case it turns out to be a very simple problem and hence also a simple solution...

The 'content' of the message is loaded at this step:

var sc = new StringContent(json, Encoding.UTF8, MediaTypeNames.Application.Json);

As you can see the MediaType is identified as "application/json" Unfortunately SharePoint expects an identifier of "application/json;odata=<verbose || nometadat>;"

So the Content.Headers.ContentType needs to be modified after it has been created (or optionally created with the correct Content.Headers.ContentType setting.

i.e. if deliver pre-generated content, then adjust the request.Content.Headers.ContentType

public Task<HttpResponseMessage> GetHttpResponseFromRequestWithBody(string url, HttpMethod method, HttpContent content, string xHttpMethod, string odata = OData.NOMETADATA)
{
    var request = GetHttpRequestMessage(url, method, xHttpMethod, odata);
    request.Content = content;
    request.Content.Headers.ContentType = MediaTypeWithQualityHeaderValue.Parse($"application/json;odata={odata}");

    return httpClient.SendAsync(request);
}

or, if you intend to create the content from a string:

public Task<HttpResponseMessage> GetHttpResponseFromRequestWithBody(string url, HttpMethod method, string content, string xHttpMethod, string odata = OData.NOMETADATA)
{
    var request = GetHttpRequestMessage(url, method, xHttpMethod, odata);
    request.Content = new StringContent(content, Encoding.UTF8, MediaTypeWithQualityHeaderValue.Parse($"application/json;odata={odata}"));
    return httpClient.SendAsync(request);
}
发布评论

评论列表(0)

  1. 暂无评论