I want to upload a static file to SharePoint using Graph API and HTTP Client.
We have a folder where the file is kept, now we have to read the file from the folder and upload it to SharePoint.
Stream stream = GetFile() //this will return file data as a Stream.
HttpClient httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization
= new AuthenticationHeaderValue("Bearer", token);
MultipartFormDataContent form = new MultipartFormDataContent();
var streamContent = new StreamContent(stream);
var imageContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
form.Add(imageContent, "Test.pdf");
var response = httpClient.PostAsync(#"https://graph.microsoft.com/v1.0/sites/{siteId}/lists/{folderName}/drive/root:/childFolder/Test.pdf:/createUploadSession", form).Result;
We are getting BadRequest response for the above request.
According to the documentation no request body is required for createUploadSession endpoint but if you specify the body it must be json like this
Content-Type: application/json
{
"item": {
"#odata.type": "microsoft.graph.driveItemUploadableProperties",
"#microsoft.graph.conflictBehavior": "rename",
"name": "largefile.dat"
}
}
The response will contain uploadSession resource type.
To upload the file, or a portion of the file, you need to make a PUT request to the uploadUrl value received in the createUploadSession response. You can upload the entire file, or split the file into multiple byte ranges, as long as the maximum bytes in any given request is less than 60 MiB.
Resources:
driveItemUploadableProperties
uploadSession
Upload bytes to the upload session
Related
I am trying to upload a file using an httpClient as an octet-stream
Following documentation is provided
HTTP Verb => POST
Content–Type => application/octet-stream
Accept => application/json
Authorization => Bearer {access token}
x-file-name => Test file.pdf
x-convert-document (optional) => true
x-source => the source (can be any string)
Request Body => file (binary Stream)
Side note : in my code below the Accept and Bearer headers and their values are already present in the Client I am fetching with the "await GetRestClientAsync()"
I expect a response back, but for now I am getting nothing back the application just stops, what am I doing wrong here?
Ps: Other Posts, request towards this api work fine with the same client I use here, so it's most likely that I am messing something up with the MultiPartFormDataContent
protected async Task<TResponse> ExecutePostAsBinaryCustomHeadersAsync<TResponse>(Uri apiUri, Stream fileStream, string fileName ,bool returnDefaultObjectForInternalServerError = false)
{
using (var formData = new MultipartFormDataContent())
{
formData.Add(new StringContent(fileName), "x-file-name");
formData.Add(new StringContent("true"), "x-convert-document");
formData.Add(new StringContent("Agion"), "x-source");
formData.Add(new StringContent("application/octet-stream"), "Content-Type");
using (var client = await GetRestClientAsync())
{
StreamContent content = new StreamContent(fileStream);
formData.Add(content, "file", fileName);
using (var response = await client.PostAsync(apiUri, formData))
{
return await DeserializeResponseAsync<TResponse>(response, returnDefaultObjectForInternalServerError);
}
}
}
}
I have a HttpResponse object as a result of HttpClient.SendAsync() call. The response has a chunked transfer encoding and results in 1.5 GB of data.
I want to pass this data through OWIN pipeline. To do this I need to convert it to a stream. Simplified code to do this is:
public async Task Invoke(IDictionary<string, object> environment)
{
var httpContent = GetHttpContent();
var responseStream = (Stream)environment["owin.ResponseBody"];
await httpContent.CopyToAsync(responseStream);
}
However, the last line results in copying the entire stream to the memory. And when I use wget to download the data directly from the backend server, it is downloaded successfully and shows a progress bar (although it doesn't know the overall size since it is chunked). But when I use wget to download data from my OWIN-hosted application it sticks on sending the request.
How should I stream this data through an OWIN pipeline to prevent copying it to memory?
EDIT
This is how I get the HttpResponse:
var client = new HttpClient(new HttpClientHandler());
// …and then:
using (var request = new HttpRequestMessage { RequestUri = uri, Method = HttpMethod.Get })
{
return client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).Result;
}
I assume this is in IIS? System.Web also buffers responses: https://msdn.microsoft.com/en-us/library/system.web.httpresponse.bufferoutput(v=vs.110).aspx
See server.DisableResponseBuffering in
https://katanaproject.codeplex.com/wikipage?title=OWIN%20Keys&referringTitle=Documentation
I am using Web API to serve the requests for files. File may be on disk or on some other server. The API controller sends a forward request or reads the file from the system and returns it.
public HttpResponseMessage GetResponse(string uri, HttpRequestMessage request)
{
HttpResponseMessage response = new HttpResponseMessage();
try
{
string newUrl = MapUrl(uri);
Stream responseStream = CreateResponse(request, newUrl);
response.Content = new StreamContent(responseStream);
return response;
}
catch (Exception ex)
{
response.StatusCode = HttpStatusCode.NotFound;
response.Content = new StringContent(ex.ToString());
return response;
}
}
CreateResponse() either returns a FileStream or GetResponseStream() based on the current configuration.
No Content-Length header is being added as the file is being streamed, in the response headers I see Transfer-Encoding: chunked header as expected.
But in case the file has to be served by reading from the filesystem IIS automatically adds the Content-Length header - which should not have happened as the file is being read as a stream by the code,
return new FileStream(newUrl, FileMode.Open);
any custom headers added show up confirming response was sent by the code and not IIS directly.
In global.asax routes.RouteExistingFiles = true;
I'm trying to call this API from my C# app:
https://ocr.space/OCRAPI
When I call it from curl, it just works fine:
curl -k --form "file=#filename.jpg" --form "apikey=helloworld" --form "language=eng" https://api.ocr.space/Parse/Image
I implemented it this way:
[TestMethod]
public async Task Test_Curl_Call()
{
var client = new HttpClient();
String cur_dir = Directory.GetCurrentDirectory();
// Create the HttpContent for the form to be posted.
var requestContent = new FormUrlEncodedContent(new[] {
new KeyValuePair<string, string>( "file", "#filename.jpg"), //I also tried "filename.jpg"
new KeyValuePair<string, string>( "apikey", "helloworld" ),
new KeyValuePair<string, string>( "language", "eng")});
// Get the response.
HttpResponseMessage response = await client.PostAsync(
"https://api.ocr.space/Parse/Image",
requestContent);
// Get the response content.
HttpContent responseContent = response.Content;
// Get the stream of the content.
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
// Write the output.
String result = await reader.ReadToEndAsync();
Console.WriteLine(result);
}
}
I get this answer :
{
"ParsedResults":null,
"OCRExitCode":99,
"IsErroredOnProcessing":true,
"ErrorMessage":"No file uploaded or URL provided",
"ErrorDetails":"",
"ProcessingTimeInMilliseconds":"0"
}
Any clue?
What's the # character for in "file=#filename.jpg"?
I put my filename.jpg file in the project and test project bin/debug directory and run my test project in debug mode.
So I don't think the error points to the file not being where expected.
I'd rather suspect a syntax error in my code.
The error message is telling you what's wrong:
No file uploaded or URL provided
You sent a filename to the service in your code, but that's not the same thing as giving curl a filename. curl is smart enough to read the file and upload the contents with your request, but in your C# code, you'll have to do that yourself. The steps will be:
Read the file bytes from disk.
Create a multipart request with two parts: the API key ("helloworld"), and the file bytes.
POST this request to the API.
Fortunately, it's pretty easy. This question demonstrates the syntax to set up a multipart request.
This code worked for me:
public async Task<string> TestOcrAsync(string filePath)
{
// Read the file bytes
var fileBytes = File.ReadAllBytes(filePath);
var fileName = Path.GetFileName(filePath);
// Set up the multipart request
var requestContent = new MultipartFormDataContent();
// Add the demo API key ("helloworld")
requestContent.Add(new StringContent("helloworld"), "apikey");
// Add the file content
var imageContent = new ByteArrayContent(fileBytes);
imageContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
requestContent.Add(imageContent, "file", fileName);
// POST to the API
var client = new HttpClient();
var response = await client.PostAsync("https://api.ocr.space/parse/image", requestContent);
return await response.Content.ReadAsStringAsync();
}
I have a app in which user can record video and an api to upload recorded video to azure. I am using below code
HttpClientHandler handler = new HttpClientHandler();
handler.MaxRequestContentBufferSize = int.MaxValue;
using (HttpClient httpClient = new HttpClient(handler)
{
MaxResponseContentBufferSize = int.MaxValue
})
{
MultipartFormDataContent content = new MultipartFormDataContent();
content.Add(new ByteArrayContent(chunks), "file", fileName);
HttpResponseMessage response = null;
response = await httpClient.PostAsync(new Uri(url), content);
return await response.Content.ReadAsStringAsync();
}
This is working only when either connection is wifi or on 3G video is less than of 10 sec. When I tried to upload video of size around 20-30 MB than it fails. In response I got status code 404 Not Found.
I also tried another way to upload but caught same error.
At last, I have changed my api code and send request with 1 mb chunks.