Downloading PDF across 2 APIs using GET request - c#

Im trying to download a PDF file crossing over two API's with a GET Request.
If I go direct to API2 the PDF downloads fine with the below code:
Stream fileStream = File.Open(fileLocation, FileMode.Open);
result.Content = new StreamContent(fileStream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "test.pdf"
};
return result;
However when I throw API1 into the mix things get a little wonky!!
using (System.Net.Http.HttpClient client = new System.Net.Http.HttpClient())
{
var httpRequestMessage = new HttpRequestMessage();
httpRequestMessage.Method = HttpMethod.Get;
httpRequestMessage.RequestUri = new Uri(requestUrl);
HttpResponseMessage response = await client.SendAsync(httpRequestMessage);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var content = await response.Content.ReadAsStringAsync();
response.Content = new StringContent(content);
response.EnsureSuccessStatusCode();
response.Content.Headers.ContentEncoding.Add("UTF8");
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "test.pdf"
};
return response;
Going direct to API2 produces: %PDF-1.6%âãÏÓ
Going via API2 produces:%PDF-1.6%����
Ive tried changing ContentType and ContentEncoding on API1 with no joy.
Does anything jump out to anyone?

Calling .ReadAsStringAsync on a binary document wont work - you have to call .ReadAsByteArrayAsync.
You also have to use ByteArrayContent instead of StringContent.
not tested

Related

Using C# HttpClient to POST File without multipart/form-data

I'm trying to interact with a API that doesn't support multipart/form-data for uploading a file.
I've been able to get this to work with the older WebClient but since it's being deprecated I wanted to utilize the newer HttpClient.
The code I have for WebClient that works with this end point looks like this:
using (WebClient client = new WebClient())
{
byte[] file = File.ReadAllBytes(filePath);
client.Headers.Add("Authorization", apiKey);
client.Headers.Add("Content-Type", "application/pdf");
byte[] rawResponse = client.UploadData(uploadURI.ToString(), file);
string response = System.Text.Encoding.ASCII.GetString(rawResponse);
JsonDocument doc = JsonDocument.Parse(response);
return doc.RootElement.GetProperty("documentId").ToString();
}
I've not found a way to get an equivalent upload to work with HttpClient since it seems to always use multipart.
I think it would look something like this
using var client = new HttpClient();
var file = File.ReadAllBytes(filePath);
var content = new ByteArrayContent(file);
content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
var result = await client.PostAsync(uploadURI.ToString(), content);
result.EnsureSuccessStatusCode();
var response = await result.Content.ReadAsStringAsync();
var doc = JsonDocument.Parse(response);
return doc.RootElement.GetProperty("documentId").ToString();
What speaks against using simply HttpClient's PostAsync method in conjunction with ByteArrayContent?
byte[] fileData = ...;
var payload = new ByteArrayContent(fileData);
payload.Headers.Add("Content-Type", "application/pdf");
myHttpClient.PostAsync(uploadURI, payload);

ReasonPhrase Not Acceptable HTTPClient C#

I am trying to send a json object with a base4 encoded file to a web api service using the code below
MemoryStream target = new MemoryStream();
q.fileUpload.InputStream.CopyTo(target); //q.fileUpload is an HttpPostedFilebase pdf
var myfile= Convert.ToBase64String(target.ToArray());
var requestbody = new {
filedata = new
{
mimetype = "application/pdf",
basedata = "base64-data=" + myfile
}
};
var jsondata = JsonConvert.SerializeObject(requestbody );
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("https://web.base.url/");
client.DefaultRequestHeaders.Add("X-API-KEY", "SOMEAPIKEY");
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "upload");
request.Content = new StringContent(jsondata, Encoding.UTF8, "application/json");
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var responsetask= client.SendAsync(request);
return Json(responsetask);
But i everytime i call this i get a 406 Not Acceptable response. Anyone knows what causes it?

How to convert a HttpResponse StreamContent to zip file?

I have an API which is returning HTTPResponse with Content of type "Stream Content". Now i want to consume this API in another application and download the zip file sent as stream content. Can someone please suggest how can I achieve this in C#?
private HttpResponseMessage GetHttpResponseMessageForConfigFile(Component component)
{
var result = Request.CreateResponse(HttpStatusCode.OK);
component.ConfigData = _configDataService.GetConfigDetail(component.Id).Data;
var mermoryStream = new MemoryStream(component.ConfigData);
result.Content = new StreamContent(mermoryStream);
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = string.Format("{0}.zip", component.Code)
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return result;
}
In the above, component.ConfigData contains a byte array of zip file.
You download a ZIP file like any other binary file as well:
using (WebClient client = new WebClient())
{
client.DownloadFile(new Uri(url), #"c:\path\to\file.zip");
}

Voicebase API in c#

I am working on how to upload a media file using the VoiceBase API. I tried using HttpClient ( with MultipartFormDataContent and FormUrlEncodedContent), RestClient , WebClient and WebRequest. But it didn't worked.
Following is the code I tried:
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "xxxx");
MultipartFormDataContent form = new MultipartFormDataContent();
form.Add(new StringContent("http:/xx.mp3"), "media", "testFile.mp3");
HttpResponseMessage response = await client.PostAsync("https://apis.voicebase.com/v2-beta/media", form);
HttpContent responseContent = response.Content;
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
var a = reader.ReadToEndAsync();
return response;
}
API returns this error:
"status": 400,
"errors":
{
"error": "We have identified 1 error in your request: (1) Your upload was rejected because the media file not be successfully parsed (80 bytes )."
},
"reference": "3D00BCA8:A910_0A40E32A:01BB_5949122A_69009:79C6"
}
Edit
I have also tried with binary data:
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "xxxx");
MultipartFormDataContent form = new MultipartFormDataContent();
form.Add(new ByteArrayContent(File.ReadAllBytes(#"C:\Users\xxxx.mp3")), "media", "xxxx.mp3");
HttpResponseMessage response = await client.PostAsync("https://apis.voicebase.com/v2-beta/media", form);
HttpContent responseContent = response.Content;
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
var a = reader.ReadToEndAsync();
return response;
}
With binary data I was getting following error:
{
"status": 400,
"errors":
{
"error": "We have identified 1 error in your request: (1) We could not download the URL"
}
,
"reference": "3D00BCA8:DFF5_0A40E32A:01BB_59491448_6F33E:79C6"
}
I needed to do this today so I've made an attempt to wrap up my work on the V3 API in a nuget package here:
https://www.nuget.org/packages/VoiceBaseV3/
When I get the time I'll get it on GitHub too
The first parameter of your form.Add(...) needs to be a data stream of the contents of the actual file, not a string. To do this you can make a new memory stream like this: new MemoryStream(File.ReadAllBytes(localfilePath))
Try this:
var content = new StreamContent(new FileStream(#"C:\Users\xxxx.mp3", FileMode.Open));
content.Headers.ContentType = new MediaTypeHeaderValue("audio/mp3");
MultipartFormDataContent form = new MultipartFormDataContent();
form.Add(content, "media", "xxxx.mp3");
If you use V3, you can generate the client code with Swagger on the language of your preference
https://voicebase.readthedocs.io/en/v3/how-to-guides/swagger-codegen.html

Web Api 2 not returning ByteArrayContent to HTTPClient

I am putting together a test application using WebApi2 and HttpClient in a win forms app.
I have come accross an issue where my HttpClient request to a WebApi2 controller which returns an HttpResponseMessage doesnt return the ByteArrayContent.
WebApiController Code
[HttpGet]
public HttpResponseMessage DownloadFilePart(string fileName)
{
var path = Server.MapPath("~/App_Data/uploads/" + fileName);
var fileArray = System.IO.File.ReadAllBytes(path);
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(fileArray)
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue(System.Web.MimeMapping.GetMimeMapping(fileName));
response.Content.Headers.ContentLength = fileArray.Length;
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = fileName
};
return response;
}
WinForms Code using HttpClient
static async void GetFilePart(string hostrUri)
{
var httpClient = new HttpClient
{
BaseAddress = new Uri(hostrUri)
};
var request = new HttpRequestMessage(HttpMethod.Get, "/Home/DownloadFilePart/?fileName=Test.txt");
var responseMessage = httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
var memoryStream = new MemoryStream();
var stream = await responseMessage.Result.Content.ReadAsByteArrayAsync();
var fileToWriteTo = System.IO.Path.GetDirectoryName(Application.ExecutablePath) + "\\Temp\\Test.txt";
using (var fileStream = new FileStream(fileToWriteTo, FileMode.Create, FileAccess.Write, FileShare.None))
{
//copy the content from response to filestream
fileStream.Write(stream, 0, stream.Length);
}
}
When the request return from the WebApi and I write the bytes to file all that is written into the file is the actual headers from the WebApi response. Has anyone any ideas what the issue could be here?
Thanks
Your problem is here
httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
HttpCompletionOption.ResponseHeadersRead is summarized as
The operation should complete as soon as a response is available and headers are read. The content is not read yet.
This would explain why you only get the headers in your response.
Either remove it completely or change it to HttpCompletionOption.ResponseContentRead
static async void GetFilePart(string hostrUri)
{
var httpClient = new HttpClient
{
BaseAddress = new Uri(hostrUri)
};
var request = new HttpRequestMessage(HttpMethod.Get, "/Home/DownloadFilePart/?fileName=Test.txt");
var responseMessage = await httpClient.SendAsync(request);
var byteArray = await responseMessage.Content.ReadAsByteArrayAsync();
var fileToWriteTo = System.IO.Path.GetDirectoryName(Application.ExecutablePath) + "\\Temp\\Test.txt";
using (var fileStream = new FileStream(fileToWriteTo, FileMode.Create, FileAccess.Write, FileShare.None))
{
//copy the content from response to filestream
fileStream.Write(byteArray, 0, byteArray.Length);
}
}

Categories