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 badges1 Answer
Reset to default 2As 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);
}