RestSharp.Portable read File from Stream - c#

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);
}
}

Related

Task was cancelled when trying to download file from WebApi

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.

WebAPI returns corrupted, incomplete file

I want to return an image from WebApi endpoint. This is my method:
[System.Web.Http.HttpGet]
public HttpResponseMessage GetAttachment(string id)
{
string dirPath = HttpContext.Current.Server.MapPath(Constants.ATTACHMENT_FOLDER);
string path = string.Format($"{dirPath}\\{id}.jpg");
try
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
var content = new StreamContent(stream);
result.Content = content;
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") { FileName = Path.GetFileName(path) };
return result;
}
catch (FileNotFoundException ex)
{
_log.Warn($"Image {path} was not found on the server.");
return Request.CreateResponse(HttpStatusCode.NotFound, "Invalid image ID");
}
}
Unfortunately, the file that is downloaded is incomplete. The message in consuming Android app is:
java.io.EOFException: source exhausted prematurely
The problem is most likely that your Android client thinks the download is over before it actually is.
To easily fix this, you can use this method instead which will return the entire file at once (rather than streaming it):
result.Content = new ByteArrayContent(File.ReadAllBytes(path));
Turns out that this was caused by compression, that was set for all responses in this controller. There is GZip encoding set up in controller's constructor:
HttpContext.Current.Response.AppendHeader("Content-Encoding", "gzip");
HttpContext.Current.Response.Filter = new GZipStream(HttpContext.Current.Response.Filter, CompressionMode.Compress);
To solve this, I added these lines to my method
(just after beginning of try block):
// reset encoding and GZip filter
HttpContext.Current.Response.Headers["Content-Encoding"] = "";
HttpContext.Current.Response.Headers["Content-Type"] = "";
// later content type is set to image/jpeg, and default is application/json
HttpContext.Current.Response.Filter = null;
Also, I'm setting content type and length like this:
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
result.Content.Headers.ContentLength = stream.Length;

How to pass the File Data from C# Console application to WebApi?

I am trying to call the Web api method for saving the File Data.When I debug Webapi method I found that ContentLength is not coming as correct, because of this when i am retrieving the file it is showing error as corrupted file.
My Class method is :-
using (var formData = new MultipartFormDataContent())
{
HttpContent stringContent = new StringContent(file);
formData.Add(stringContent, "file", file);
formData.Add(new StringContent(JsonConvert.SerializeObject(file.Length)), "ContentLength ");
HttpResponseMessage responseFile = client.PostAsync("Report/SaveFile?docId=" + docId, formData).Result;
}
My Web api method is :-
[HttpPost]
public HttpResponseMessage SaveFile(long docId)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Unauthorized);
try
{
var httpRequest = HttpContext.Current.Request;
bool IsSuccess = true;
if (httpRequest.Files.Count > 0)
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
HttpPostedFile postedFile = httpRequest.Files[file];
// Initialize the stream.
Stream myStream = postedFile.InputStream;
myStream.Position = 0;
myStream.Seek(0, SeekOrigin.Begin);
var _item = CorrectedReportLibrary.Services.ReportService.SaveFile(myStream,docId);
response = Request.CreateResponse<bool>((IsSuccess)
? HttpStatusCode.OK
: HttpStatusCode.NoContent,
IsSuccess);
}
}
}
catch (Exception ex)
{
Theranos.Common.Library.Util.LogManager.AddLog(ex, "Error in CorrectedReportAPI.Controllers.SaveDocument()", null);
return Request.CreateResponse<ReportDocumentResult>(HttpStatusCode.InternalServerError, null);
}
return response;
}
How can I set the ContentLength from C# class method?
It looks a bit strange that you use ContentLength as the second parameter on the StringContent class. It is suppose to be which encoding you want to use, for example
new StringContent(content, Encoding.UTF8). I don't think it is the content length that is the issue here.
StringContent class
I guess since it is a file you want to upload, you already have the file read as a stream, so I usually do something like this:
Client:
private async Task UploadFile(MemoryStream file)
{
var client = new HttpClient();
var content = new MultipartFormDataContent();
content.Add(new StreamContent(file));
var result = await client.PostAsync("Report/SaveFile?docId=" + docId, content);
}
Edit. Since it's a multipartform it's easier to let the framework handle the details. Try something like this:
Server:
[HttpPost]
public async Task<HttpResponseMessage> SaveFile(long docId)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Unauthorized);
try
{
var filedata = await Request.Content.ReadAsMultipartAsync(new MultipartMemoryStreamProvider());
foreach(var file in filedata.Contents)
{
var fileStream = await file.ReadAsStreamAsync();
}
response = Request.CreateResponse<bool>(HttpStatusCode.OK, true);
}
catch (Exception ex)
{
response = Request.CreateResponse<bool>(HttpStatusCode.InternalServerError, false);
}
return response;
}
At Last I found the solution no need to change the web api service,
issue was from client where I was directly passing the file data, Now the modified
working code is like this:-
using (var formData = new MultipartFormDataContent())
{
var bytes = File.ReadAllBytes(file);
formData.Add(new StreamContent(new MemoryStream(bytes)), "file", file);
HttpResponseMessage responseFile = client.PostAsync("ReportInfo/SaveFile?docId=" + docId, formData).Result;
}

How to return a IHttpActionResult with Http status code 200 and pass in a memory stream in the http response

In my APIController.cs Get() method, how can I return a IHttpActionResult with HTTP status code 200 and pass in a memory stream in the HTTP response?
I tried doing this:
var sr = new StreamReader(myMemoryStream);
string myStr = sr.ReadToEnd();
return Ok(myStr);
But it converts my memory stream to string and pass that to Ok(). But I don't want to my memory stream to stream before sending in http respone.
And I don't see any method in the OkResult object which allows me to set the response stream.
How can I set the http response body?
public HttpResponseMessage GetFile()
{
byte[] byteArray;
using (MemoryStream memoryStream = new MemoryStream())
{
// Do you processign here
byteArray = memoryStream.ToArray();
}
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new ByteArrayContent(byteArray);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
//suppose its .xlsx file
response.Content.Headers.ContentDisposition.FileName = "Sample.xlsx";
return response;
}
if you are returning IHttpActionResult, then return
return ResponseMessage(GetFile());
Please let me know if you want client side code also
Try this code
public IHttpActionResult GetStream()
{
MemoryStream myMemoryStream = new MemoryStream();
var sr = new System.IO.StreamReader(myMemoryStream);
string myStr = sr.ReadToEnd();
return Ok(myStr);
}

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