ASP.NET Web API to return images - c#

I've been spinning my tires trying to use ASP.NET Web API to return images. I've seen a number of examples, but I keep running into problems.
After searching for a solution, most examples suggest using HttpResponseMessage and setting the Content and Content-Type header correctly. For example in the following posts:
WebApi: How to handle Images ASP .Net Web API downloading images as binary
Here's what I am doing now:
[System.Web.Http.HttpGet]
[ActionName("ConvertHTMLToImage")]
public HttpResponseMessage ConvertHTMLToImage(string htmlString)
{
var path = #"C:\temp\mona-lisa.png";
var response = Request.CreateResponse(HttpStatusCode.OK);
var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
response.Content = new StreamContent(fileStream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
return response;
}
I'm getting mixed results. When I go the URL for that resource I have problems with Chrome (This webpage is not available), Firefox (The connection was reset), and Safari (Safari can’t open the page). Much to my surprise, it works fine in IE. I can also successfully view the image using the composer in Fiddler. If I keep Fiddler open and access the resource using Chrome/Firefox/Safari, I see 504 errors. Not sure what the means, I can't remember ever having seen that error type before.
I also noticed some strange behavior in the debugger with the browsers that aren't working. If I call ConvertHTMLToImage from IE and Fiddler, I see it stop at my break-point once and then the image is sucessfully returned to the client. On Chrome/Firefox/Safari there are multiple calls into the method. Sometimes twice sometimes 3 times. I have no explanation for this. I don't get any errors that I can detect other than the browser doesn't show the image.
I've done this same thing using aspx pages, HttpHhandlers, and other .NET methods so I know there are work-arounds, but I really would like to know what I'm doing wrong. This seems like something that should be easily accomplished using the Web API.

This solved the issue for me WebApi: How to handle Images
In short
[System.Web.Http.HttpGet]
[ActionName("ConvertHTMLToImage")]
public HttpResponseMessage ConvertHTMLToImage()
{
string filePath = #"C:\temp\mona-lisa.png";
var result = new HttpResponseMessage(HttpStatusCode.OK);
FileStream fileStream = new FileStream(filePath, FileMode.Open);
Image image = Image.FromStream(fileStream);
MemoryStream memoryStream = new MemoryStream();
image.Save(memoryStream, ImageFormat.Jpeg);
result.Content = new ByteArrayContent(memoryStream.ToArray());
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
return result;
}

I used this recently in my project:
public HttpResponseMessage Get(int IRN)
{
try
{
Multimedia image = new Multimedia();
MemoryStream imageStream = image.GetMedia(IRN);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(imageStream);
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
return response;
}
catch (Exception ex)
{
return HandleError(ex);
}
}
GetMedia function:
.....
MemoryStream mediaStream = new MemoryStream();
...
FileStream temp = resource["file"] as FileStream;
mediaStream.SetLength(temp.Length);
temp.Read(mediaStream.GetBuffer(), 0, (int)temp.Length);
temp.Close();
....
return mediaStream;
resource["file"] is an array which contained a filestream object.
Hope this helps.

Try this(replace jpg with png as desired):
var result = new HttpResponseMessage(HttpStatusCode.OK);
String filePath = HostingEnvironment.MapPath("~/Images/123.jpg");
FileStream fileStream = new FileStream(filePath, FileMode.Open);
Image image = Image.FromStream(fileStream);
MemoryStream memoryStream = new MemoryStream();
image.Save(memoryStream, ImageFormat.Jpeg);
var byteArrayContent = new ByteArrayContent(memoryStream.ToArray());
byteArrayContent.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
result.Content = byteArrayContent;
return result;

Related

Can save stream as local file, but when returning it as HttpResponseMessage - always empty file

I want to write export/download functionality for files from external API.
I've created separate Action for it. Using external API I can get stream for that file.
When I am saving that stream to local file, everything is fine, file isn't empty.
var exportedFile = await this.GetExportedFile(client, this.ReportId, this.WorkspaceId, export);
// Now you have the exported file stream ready to be used according to your specific needs
// For example, saving the file can be done as follows:
string pathOnDisk = #"D:\Temp\" + export.ReportName + exportedFile.FileSuffix;
using (var fileStream = File.Create(pathOnDisk))
{
await exportedFile.FileStream.CopyToAsync(fileStream);
}
But when I return exportedFile object that contains in it stream and do next:
var result = await this._service.ExportReport(reportName, format, CancellationToken.None);
var fileResult = new HttpResponseMessage(HttpStatusCode.OK);
using (var ms = new MemoryStream())
{
await result.FileStream.CopyToAsync(ms);
ms.Position = 0;
fileResult.Content = new ByteArrayContent(ms.GetBuffer());
}
fileResult.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = $"{reportName}{result.FileSuffix}"
};
fileResult.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return fileResult;
Exported file is always empty.
Is it problem with stream or with code that try to return that stream as file?
Tried as #Nobody suggest to use ToArray
fileResult.Content = new ByteArrayContent(ms.ToArray());
the same result.
Also tried to use StreamContent
fileResult.Content = new StreamContent(result.FileStream);
still empty file.
But when I'm using StreamContent and MemmoryStream
using (var ms = new MemoryStream())
{
await result.FileStream.CopyToAsync(ms);
ms.Position = 0;
fileResult.Content = new StreamContent(ms);
}
in result I got
{
"error": "no response from server"
}
Note: from 3rd party API I get stream that is readonly.
you used GetBuffer() to retrieve the data of the memory stream.
The function you should use is ToArray()
Please read the Remarks of the documentation of these functions.
https://learn.microsoft.com/en-us/dotnet/api/system.io.memorystream.getbuffer?view=net-6.0
using (var ms = new MemoryStream())
{
ms.Position = 0;
await result.FileStream.CopyToAsync(ms);
fileResult.Content = new ByteArrayContent(ms.ToArray()); //ToArray() and not GetBuffer()
}
Your "mistake" although it's an obvious one is that you return a status message, but not the actual file itself (which is in it's own also a 200).
You return this:
var fileResult = new HttpResponseMessage(HttpStatusCode.OK);
So you're not sending a file, but a response message. What I'm missing in your code samples is the procedure call itself, but since you use a HttpResonseMessage I will assume it's rather like a normal Controller action. If that is the case you could respond in a different manner:
return new FileContentResult(byteArray, mimeType){ FileDownloadName = filename };
where byteArray is ofcourse just a byte[], the mimetype could be application/octet-stream (but I suggest you'd actually find the correct mimetype for the browser to act accordingly) and the filename is the filename you want the file to be named.
So, if you were to stitch above and my comment together you'd get this:
var exportedFile = await this.GetExportedFile(client, this.ReportId, this.WorkspaceId, export);
// Now you have the exported file stream ready to be used according to your specific needs
// For example, saving the file can be done as follows:
string pathOnDisk = #"D:\Temp\" + export.ReportName + exportedFile.FileSuffix;
using (var fileStream = File.Create(pathOnDisk))
{
await exportedFile.FileStream.CopyToAsync(fileStream);
}
return new FileContentResult(System.IO.File.ReadAllBytes(pathOnDisk), "application/octet-stream") { FileDownloadName = export.ReportName + exportedFile.FileSuffix };
I suggest to try it, since you still report a 200 (and not a fileresult)

Web API 2 Getting ZIP files returned strange symbols

As I was trying to get a zip file from my one of my dir through API, I always get this random or strange symbols.
var path = D:\\Source\\API\\TEST\\XMLPDF\\test.zip;
HttpResponseMessage reponse = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(path, FileMode.Open, FileAccess.Read);
reponse.Content = new StreamContent(stream);
reponse.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
return reponse;
I've used the code above to return the zip file.
I've added a screenshot from the return body of postman.
Has anyone encountered this kind of issue?

C# Web.API Returning image. MemoryStream -> StreamContent returns browken image

I need to return from web service an image that is stored at the disk.
In my controller I perform some search operations and send file. Here is my code.
public HttpResponseMessage Get([FromUri]ShowImageRequest req)
{
// .......................
// .......................
// load image file
var imgStream = new MemoryStream();
using (Image image = Image.FromFile(fullImagePath))
{
image.Save(imgStream, ImageFormat.Jpeg);
}
imgStream.Seek(0, SeekOrigin.Begin); // it does not work without this
var res = new HttpResponseMessage(HttpStatusCode.OK);
res.Content = new StreamContent(imgStream);
res.Content.Headers.ContentType = new ediaTypeHeaderValue("image/jpeg");
return res;
}
If I do not add this line, I see in fiddler response body length 0
imgStream.Seek(0, SeekOrigin.Begin);
Otherwise it works. What am I missing and why do I need to do this?
After saving the stream position is at the end. This means that reading from it returns no bytes.
Everyone runs into this exact issue once :)

Sending Image from C# to Android via JSON

I have images stored in SQL server, and I want to send them to Android app via JSON with other data. What's the best way to do this?
BTW my server side written in ASP Web API(C#).
In other way I want to make my image like this http://myserver/image.jpg
so I can included in my JSON and download it in Android app.
As its not where clear from your question, This Link is the best what I can find for you. In it he is accessing ASP.NET WebAPI and converting all the things to JSON when access or pass it through the Andriod studio
http://hintdesk.com/how-to-call-asp-net-web-api-service-from-android/
and here is a complete series that can help you more
http://www.tutecentral.com/restful-api-for-android-part-1/
Hope this helps
I finally figure it out
This is the code
public HttpResponseMessage getImage(String name)
{
name = name + ".png";
var result = new HttpResponseMessage(HttpStatusCode.OK);
String filePath = HostingEnvironment.MapPath("~/images/"+name);
FileStream fileStream = new FileStream(filePath, FileMode.Open);
Image image = Image.FromStream(fileStream);
MemoryStream memoryStream = new MemoryStream();
image.Save(memoryStream, ImageFormat.Jpeg);
result.Content = new ByteArrayContent(memoryStream.ToArray());
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
fileStream.Dispose();
return result;
}

C# Serving a stream to a browser - can it be done?

I am trying to output a file to the browser from a REST API - but I don't have a physical file, instead I have a MemoryStream (and I would prefer not to write a physical file).
This works:
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(path, FileMode.Open);
result.Content = new StreamContent(stream);
return result;
This does not:
var stream = new MemoryStream();
// Iterate DataReader and populate MemoryStream code omitted for brevity.
// Assume MemoryStream has been written to correctly and contains data.
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(stream);
return result;
This has consumed most of my weekend so I would be delighted if anyone can offer some definitive insight.
I've found the answer through trial and error and a lot of research:
Yes, it can be done.
Instead of using StreamContent use ByteArrayContent:
e.g.
result.Content = new ByteArrayContent( stream.GetBuffer() );
Ensure that there is no HttpResponseMessage.ContentLength set or it will fail to work (connection reset) - it took me hours to figure that out.

Categories