Task was cancelled when trying to download file from WebApi - c#

I got the error "Task was cancelled" when I'm trying to download a zip file from Web API. What am I doing wrong ?
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Threading.Tasks.TaskCanceledException: A task was canceled.
using (var ms = new MemoryStream())
{
using (var zipArchive = new ZipArchive(ms, ZipArchiveMode.Create, true))
{
foreach (var attachment in item)
{
var entry = zipArchive.CreateEntry(attachment.ItemAnalisado.Arquivo.Nome, CompressionLevel.Fastest);
using (var stream = entry.Open())
{
var dadosArquivo = File.ReadAllBytes(
Path.Combine(CaminhoImagens,
attachment.ItemAnalisado.Arquivo.ProcessoId.ToString(),
attachment.ItemAnalisado.Arquivo.SubPastaId.ToString(),
attachment.ItemAnalisado.Arquivo.Id.ToString()));
stream.Write(dadosArquivo, 0, dadosArquivo.Length);
//stream.Position = 0;
stream.Close();
}
}
}
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
ms.Position = 0;
response.Content = new StreamContent(ms);
ms.Dispose();
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "teste.zip";
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/zip");
return response;
}

I was getting this error while trying to download an Excel file calling my API. I didn't had ATP implemented on this method so it was confusing at first. This was my initial code:
public IHttpActionResult Get([FromUri] string id, [FromUri] SurveyReportRequestType requestType) {
byte[] excelData = System.Text.Encoding.UTF8.GetBytes("Boobs out!");
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
using (var stream = new MemoryStream(excelData))
{
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "Data.xls"
};
}
return ResponseMessage(result);
}
After thinking and making some changes this came up:
...
byte[] excelData = System.Text.Encoding.UTF8.GetBytes("Boobs aout!");
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new MemoryStream(excelData);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "Data.xls"
};
return ResponseMessage(result);
...
As you can see I was enclosing the stream inside an using statement. This was causing that the request wasn't being completed since the content was not available for the response.

Related

How to implement WebClient.UploadFileAsync with HttpClient? [duplicate]

Does anyone know how to use the HttpClient in .Net 4.5 with multipart/form-data upload?
I couldn't find any examples on the internet.
my result looks like this:
public static async Task<string> Upload(byte[] image)
{
using (var client = new HttpClient())
{
using (var content =
new MultipartFormDataContent("Upload----" + DateTime.Now.ToString(CultureInfo.InvariantCulture)))
{
content.Add(new StreamContent(new MemoryStream(image)), "bilddatei", "upload.jpg");
using (
var message =
await client.PostAsync("http://www.directupload.net/index.php?mode=upload", content))
{
var input = await message.Content.ReadAsStringAsync();
return !string.IsNullOrWhiteSpace(input) ? Regex.Match(input, #"http://\w*\.directupload\.net/images/\d*/\w*\.[a-z]{3}").Value : null;
}
}
}
}
It works more or less like this (example using an image/jpg file):
async public Task<HttpResponseMessage> UploadImage(string url, byte[] ImageData)
{
var requestContent = new MultipartFormDataContent();
// here you can specify boundary if you need---^
var imageContent = new ByteArrayContent(ImageData);
imageContent.Headers.ContentType =
MediaTypeHeaderValue.Parse("image/jpeg");
requestContent.Add(imageContent, "image", "image.jpg");
return await client.PostAsync(url, requestContent);
}
(You can requestContent.Add() whatever you want, take a look at the HttpContent descendant to see available types to pass in)
When completed, you'll find the response content inside HttpResponseMessage.Content that you can consume with HttpContent.ReadAs*Async.
This is an example of how to post string and file stream with HTTPClient using MultipartFormDataContent. The Content-Disposition and Content-Type need to be specified for each HTTPContent:
Here's my example. Hope it helps:
private static void Upload()
{
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("User-Agent", "CBS Brightcove API Service");
using (var content = new MultipartFormDataContent())
{
var path = #"C:\B2BAssetRoot\files\596086\596086.1.mp4";
string assetName = Path.GetFileName(path);
var request = new HTTPBrightCoveRequest()
{
Method = "create_video",
Parameters = new Params()
{
CreateMultipleRenditions = "true",
EncodeTo = EncodeTo.Mp4.ToString().ToUpper(),
Token = "x8sLalfXacgn-4CzhTBm7uaCxVAPjvKqTf1oXpwLVYYoCkejZUsYtg..",
Video = new Video()
{
Name = assetName,
ReferenceId = Guid.NewGuid().ToString(),
ShortDescription = assetName
}
}
};
//Content-Disposition: form-data; name="json"
var stringContent = new StringContent(JsonConvert.SerializeObject(request));
stringContent.Headers.Add("Content-Disposition", "form-data; name=\"json\"");
content.Add(stringContent, "json");
FileStream fs = File.OpenRead(path);
var streamContent = new StreamContent(fs);
streamContent.Headers.Add("Content-Type", "application/octet-stream");
//Content-Disposition: form-data; name="file"; filename="C:\B2BAssetRoot\files\596090\596090.1.mp4";
streamContent.Headers.Add("Content-Disposition", "form-data; name=\"file\"; filename=\"" + Path.GetFileName(path) + "\"");
content.Add(streamContent, "file", Path.GetFileName(path));
//content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
Task<HttpResponseMessage> message = client.PostAsync("http://api.brightcove.com/services/post", content);
var input = message.Result.Content.ReadAsStringAsync();
Console.WriteLine(input.Result);
Console.Read();
}
}
}
Try this its working for me.
private static async Task<object> Upload(string actionUrl)
{
Image newImage = Image.FromFile(#"Absolute Path of image");
ImageConverter _imageConverter = new ImageConverter();
byte[] paramFileStream= (byte[])_imageConverter.ConvertTo(newImage, typeof(byte[]));
var formContent = new MultipartFormDataContent
{
// Send form text values here
{new StringContent("value1"),"key1"},
{new StringContent("value2"),"key2" },
// Send Image Here
{new StreamContent(new MemoryStream(paramFileStream)),"imagekey","filename.jpg"}
};
var myHttpClient = new HttpClient();
var response = await myHttpClient.PostAsync(actionUrl.ToString(), formContent);
string stringContent = await response.Content.ReadAsStringAsync();
return response;
}
Here is another example on how to use HttpClient to upload a multipart/form-data.
It uploads a file to a REST API and includes the file itself (e.g. a JPG) and additional API parameters. The file is directly uploaded from local disk via FileStream.
See here for the full example including additional API specific logic.
public static async Task UploadFileAsync(string token, string path, string channels)
{
// we need to send a request with multipart/form-data
var multiForm = new MultipartFormDataContent();
// add API method parameters
multiForm.Add(new StringContent(token), "token");
multiForm.Add(new StringContent(channels), "channels");
// add file and directly upload it
FileStream fs = File.OpenRead(path);
multiForm.Add(new StreamContent(fs), "file", Path.GetFileName(path));
// send request to API
var url = "https://slack.com/api/files.upload";
var response = await client.PostAsync(url, multiForm);
}
Here's a complete sample that worked for me. The boundary value in the request is added automatically by .NET.
var url = "http://localhost/api/v1/yourendpointhere";
var filePath = #"C:\path\to\image.jpg";
HttpClient httpClient = new HttpClient();
MultipartFormDataContent form = new MultipartFormDataContent();
FileStream fs = File.OpenRead(filePath);
var streamContent = new StreamContent(fs);
var imageContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
imageContent.Headers.ContentType = MediaTypeHeaderValue.Parse("multipart/form-data");
form.Add(imageContent, "image", Path.GetFileName(filePath));
var response = httpClient.PostAsync(url, form).Result;
Example with preloader Dotnet 3.0 Core
ProgressMessageHandler processMessageHander = new ProgressMessageHandler();
processMessageHander.HttpSendProgress += (s, e) =>
{
if (e.ProgressPercentage > 0)
{
ProgressPercentage = e.ProgressPercentage;
TotalBytes = e.TotalBytes;
progressAction?.Invoke(progressFile);
}
};
using (var client = HttpClientFactory.Create(processMessageHander))
{
var uri = new Uri(transfer.BackEndUrl);
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", AccessToken);
using (MultipartFormDataContent multiForm = new MultipartFormDataContent())
{
multiForm.Add(new StringContent(FileId), "FileId");
multiForm.Add(new StringContent(FileName), "FileName");
string hash = "";
using (MD5 md5Hash = MD5.Create())
{
var sb = new StringBuilder();
foreach (var data in md5Hash.ComputeHash(File.ReadAllBytes(FullName)))
{
sb.Append(data.ToString("x2"));
}
hash = result.ToString();
}
multiForm.Add(new StringContent(hash), "Hash");
using (FileStream fs = File.OpenRead(FullName))
{
multiForm.Add(new StreamContent(fs), "file", Path.GetFileName(FullName));
var response = await client.PostAsync(uri, multiForm);
progressFile.Message = response.ToString();
if (response.IsSuccessStatusCode) {
progressAction?.Invoke(progressFile);
} else {
progressErrorAction?.Invoke(progressFile);
}
response.EnsureSuccessStatusCode();
}
}
}
I'm adding a code snippet which shows on how to post a file to an API which has been exposed over DELETE http verb. This is not a common case to upload a file with DELETE http verb but it is allowed. I've assumed Windows NTLM authentication for authorizing the call.
The problem that one might face is that all the overloads of HttpClient.DeleteAsync method have no parameters for HttpContent the way we get it in PostAsync method
var requestUri = new Uri("http://UrlOfTheApi");
using (var streamToPost = new MemoryStream("C:\temp.txt"))
using (var fileStreamContent = new StreamContent(streamToPost))
using (var httpClientHandler = new HttpClientHandler() { UseDefaultCredentials = true })
using (var httpClient = new HttpClient(httpClientHandler, true))
using (var requestMessage = new HttpRequestMessage(HttpMethod.Delete, requestUri))
using (var formDataContent = new MultipartFormDataContent())
{
formDataContent.Add(fileStreamContent, "myFile", "temp.txt");
requestMessage.Content = formDataContent;
var response = httpClient.SendAsync(requestMessage).GetAwaiter().GetResult();
if (response.IsSuccessStatusCode)
{
// File upload was successfull
}
else
{
var erroResult = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
throw new Exception("Error on the server : " + erroResult);
}
}
You need below namespaces at the top of your C# file:
using System;
using System.Net;
using System.IO;
using System.Net.Http;
P.S. You are seeing a number of using blocks(IDisposable pattern) in the above code snippet which doesn't look very clean. Unfortunately, the syntax of using construct doesn't support initializing multiple variables in single statement.
X509Certificate clientKey1 = null;
clientKey1 = new X509Certificate(AppSetting["certificatePath"],
AppSetting["pswd"]);
string url = "https://EndPointAddress";
FileStream fs = File.OpenRead(FilePath);
var streamContent = new StreamContent(fs);
var FileContent = new ByteArrayContent(streamContent.ReadAsByteArrayAsync().Result);
FileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("ContentType");
var handler = new WebRequestHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.ClientCertificates.Add(clientKey1);
handler.ServerCertificateValidationCallback = (httpRequestMessage, cert, cetChain, policyErrors) =>
{
return true;
};
using (var client = new HttpClient(handler))
{
// Post it
HttpResponseMessage httpResponseMessage = client.PostAsync(url, FileContent).Result;
if (!httpResponseMessage.IsSuccessStatusCode)
{
string ss = httpResponseMessage.StatusCode.ToString();
}
}
public async Task<object> PassImageWithText(IFormFile files)
{
byte[] data;
string result = "";
ByteArrayContent bytes;
MultipartFormDataContent multiForm = new MultipartFormDataContent();
try
{
using (var client = new HttpClient())
{
using (var br = new BinaryReader(files.OpenReadStream()))
{
data = br.ReadBytes((int)files.OpenReadStream().Length);
}
bytes = new ByteArrayContent(data);
multiForm.Add(bytes, "files", files.FileName);
multiForm.Add(new StringContent("value1"), "key1");
multiForm.Add(new StringContent("value2"), "key2");
var res = await client.PostAsync(_MEDIA_ADD_IMG_URL, multiForm);
}
}
catch (Exception e)
{
throw new Exception(e.ToString());
}
return result;
}

How can I download file in my folder c# ASP.NET Web API?

I need a download file in my C:\fileName.
I am send to fileName this class but it does not working ? Where is my error?
This is my code:
// POST: api/Calendar/DownloadFile
[HttpPost]
public HttpResponseMessage DownloadFile(DownloadInput fileName)
{
var result = new HttpResponseMessage(HttpStatusCode.OK);
var filePath = HttpContext.Current.Server.MapPath(#"C:\" + fileName);
var fileBytes = File.ReadAllBytes(filePath);
var fileMemStream = new MemoryStream(fileBytes);
result.Content = new StreamContent(fileMemStream);
var headers = result.Content.Headers;
headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
headers.ContentDisposition.FileName = fileName;
headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
headers.ContentLength = fileMemStream.Length;
return result;
}
This is my error:
ExceptionType: "System.NotImplementedException"
Message: "An error has occurred."
The below is for MVC:
public ActionResult DownloadFile(string fileWithFullPath)
{
var fileBytes = System.IO.File.ReadAllBytes(fileWithFullPath);
return File(fileBytes, MediaTypeNames.Application.Octet, fileName);
}
The below is for API:
public ActionResult DownloadFile()
{
var result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(fullyQualifiedFileName, FileMode.Open);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
result.Content.Headers.ContentLength = stream.Length;
string input = $"filename=test.pdf";
ContentDispositionHeaderValue contentDisposition = null;
if (ContentDispositionHeaderValue.TryParse(input, out contentDisposition))
{
result.Content.Headers.ContentDisposition = contentDisposition;
}
return this.ResponseMessage(result);
}
Based on what you are showing here, the parameter DosyaAdi is a string and it is not clear what DownloadInput is. I would suggest changing the input parameter to a string and also changing the Method to HttpGet. The second suggestion is for convention and probably not the issue.
// GET: api/Calendar/DownloadFile
[HttpGet]
public HttpResponseMessage DownloadFile(string DosyaAdi)...
good luck

RestSharp.Portable read File from Stream

We use RestSarp.Portable in our project. This works perfeclty for most of our requests.
But it doesn't work for a get requests, which sends a file via stream. I tested the request manual via browser. This is working.
It seems like RestSharp.Portable doesn't provide the method client.DownloadData(request)
so know I have to read it manual from the response.
My code is (at this moment, not working!)
var request = new RestRequest("someRequest", Method.GET);
var result = await client.Execute<HttpResponseMessage>(request);
var responseMessage = result.Data
var resultStream = await responseMessage.Content.ReadAsStreamAsync();
result.Data seams to be null. Now what am I missing? Where is my fault
(Here my api method on the server:
[Route("someRequest")]
[HttpGet]
public HttpResponseMessage getFile(){
string path = getPath(req);
try
{
MemoryStream responseStream = new MemoryStream();
Stream fileStream = File.Open(path, FileMode.Open);
fileStream.CopyTo(responseStream);
fileStream.Close();
HttpResponseMessage response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StreamContent(responseStream)
};
response.Content.Headers.ContentDisposition =
new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment")
{
FileName = Path.GetFileName(path)
};
response.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
return response;
}
catch (IOException)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
}

How to return a file from web api controller?

I'm using a MVC 5 web Api Controller, and I want to return a file:
[Route("")]
public HttpResponseMessage GetFile()
{
var statusCode = HttpStatusCode.OK;
FileStream file = XLGeneration.XLGeneration.getXLFileExigence();
return Request.CreateResponse(statusCode, file);
}
It dosn't work.
The exception from postman is:
"ExceptionMessage": "The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'."
I'm posting what worked for me as an alternative in case anybody else is having trouble.
[ActionName("File")]
[HttpGet]
public HttpResponseMessage File()
{
var response = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new System.IO.FileStream(yourFilePath, System.IO.FileMode.Open);
response.Content = new StreamContent(stream);
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
return response;
}
I returned byte[] from WebAPI controller and download PDF successfully.
I'm using iTextSharp (LGPL) 4.1.6 free PDF converter.
To install iTextSharp (LGPL / MPL), run the following command in the Package Manager Console.
Install-Package iTextSharp-LGPL -Version 4.1.6
Server side code
[Route("Export/ExportToPdf")]
public byte[] ExportToPdf(string html)
{
MemoryStream msOutput = new MemoryStream();
TextReader reader = new StringReader(html);
Document document = new Document(new Rectangle(842, 595));
PdfWriter writer = PdfWriter.GetInstance(document, msOutput);
document.Open();
document.HtmlStyleClass = #"<style>*{ font-size: 8pt; font-family:arial;}</style>";
var parsedHtmlElements = HTMLWorker.ParseToList(new StringReader(html), null);
foreach (var htmlElement in parsedHtmlElements)
{
document.Add(htmlElement as IElement);
}
document.Close();
return msOutput.ToArray();
}
Client Side Code.
//Call this function inside of AJAX success.
function ExportToPDF(data) {
//base64 To ArrayBuffer
var binaryString = window.atob(data);
var binaryLen = binaryString.length;
var bytes = new Uint8Array(binaryLen);
for (var i = 0; i < binaryLen; i++) {
var ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
}
//-------
var link = document.createElement('a');
link.href = window.URL.createObjectURL(new Blob([bytes], { type: 'application/pdf' }));
link.download = "Report.pdf";
link.click();
}
Try this...
[Route("")]
public HttpResponseMessage GetFile()
{
var result = new HttpResponseMessage(HttpStatusCode.OK);
try
{
var file = XLGeneration.XLGeneration.getXLFileExigence();
result.Content = new StreamContent(file);
result.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
var value = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
value.FileName = "Whatever your filename is";
result.Content.Headers.ContentDisposition = value;
}
catch (Exception ex)
{
// log your exception details here
result = new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
return result;
}
This should actually stream it back as a file.
Just idea:
public HttpResponseMessage GetFile()
{
FileStream file = XLGeneration.XLGeneration.getXLFileExigence();
using(var sr = new StreamReader(file))
{
content = sr.ReadToEnd();
return new HttpResponseMessage
{
Content = new StringContent(content, Encoding.UTF8, "application/json")
};
}
}

Umbraco Media Services Create Media

I need help, I am currently developing an Umbraco api which will create media programatically from a 3rd party website.
I am using the following to create the media
public HttpResponseMessage CreateMedia()
{
var mediaService = Services.MediaService;
using (WebClient client = new WebClient())
{
Stream s = client.OpenRead("http://karl.media.local/Uploads/ef093845-41dd-4620- b220-1b346a5f9b2e.jpg");
using (MemoryStream ms = new MemoryStream())
{
s.CopyTo(ms);
var mediaImage = mediaService.CreateMedia("test4", 1152, "Image");
mediaImage.SetValue("umbracoFile", "test4", ms);
mediaService.Save(mediaImage);
}
}
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent("ExternalMediaCreate", Encoding.UTF8, "application/json");
return response;
}
}
I am getting the following error on this line mediaImage.SetValue("umbracoFile", "test4", ms);:
<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Length cannot be less than zero. Parameter name: length
</ExceptionMessage>
</Error>
Any help would be appreciated,
Thanks in advance
Fixed, the issue.
I needed to load the file into a filestream so I could access the name.
public HttpResponseMessage CreateMedia()
{
var mediaService = Services.MediaService;
var request = WebRequest.Create("http://karl.media.local/Uploads/ef093845-41dd-4620-b220-1b346a5f9b2e.jpg");
var webResponse = request.GetResponse();
var responseStream = webResponse.GetResponseStream();
if (responseStream != null)
{
var originalImage = new Bitmap(responseStream);
var path = HttpContext.Current.Server.MapPath("~/_tmp/ef093845-41dd-4620-b220-1b346a5f9b2e.jpg");
originalImage.Save(path, ImageFormat.Jpeg);
FileStream fileStream = new FileStream(path, FileMode.Open);
var test = fileStream.Name;
var mediaImage = mediaService.CreateMedia("test4", 1152, "Image");
mediaImage.SetValue("umbracoFile", test, fileStream);
mediaService.Save(mediaImage);
responseStream.Dispose();
webResponse.Dispose();
originalImage.Dispose();
}
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent("ExternalMediaCreate", Encoding.UTF8, "application/json");
return response;
}

Categories

Resources