I'm trying the following code to output a image from a asp.net web api, but the response body length is always 0.
public HttpResponseMessage GetImage()
{
HttpResponseMessage response = new HttpResponseMessage();
response.Content = new StreamContent(new FileStream(#"path to image"));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
return response;
}
Any tips?
WORKS:
[HttpGet]
public HttpResponseMessage Resize(string source, int width, int height)
{
HttpResponseMessage httpResponseMessage = new HttpResponseMessage();
// Photo.Resize is a static method to resize the image
Image image = Photo.Resize(Image.FromFile(#"d:\path\" + source), width, height);
MemoryStream memoryStream = new MemoryStream();
image.Save(memoryStream, ImageFormat.Jpeg);
httpResponseMessage.Content = new ByteArrayContent(memoryStream.ToArray());
httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
httpResponseMessage.StatusCode = HttpStatusCode.OK;
return httpResponseMessage;
}
The the following:
Ensure path is correct (duh)
Ensure your routing is correct. Either your Controller is ImageController or you have defined a custom route to support "GetImage" on some other controller.
(You should get a 404 response for this.)
Ensure you open the stream:
var stream = new FileStream(path, FileMode.Open);
I tried something similar and it works for me.
Instead of a ByteArrayContent you can also use a StreamContent class to work more efficient with streams.
Related
I am in the process of creating a proxy server that makes a request to a PDF Blob link then takes the request to setup its HttpResponse Header which we sent to the client. This diagram should explain
As of now, I am successful at making the request to get the pdf content however I am not sure how to send that back to the user. I have followed other Stackoverflow post such as this one : https://stackoverflow.com/a/43232581/10541061
I turn the response message in step 3 of the diagram to a stream and sent it back in the new HttpResponseMessage content.But instead of PDF content , I get a json file
What I want to return to the client
What I am actually returning to the client
Here is the code I am using to create this proxy endpoint
[AllowAnonymous]
[HttpGet("openPDF")]
public async Task<HttpResponseMessage> OpenPDF([FromQuery] string url)
{
var _httpClient = _httpClientFactory.CreateClient();
var response = await _httpClient.GetAsync(url);
var stream = await response.Content.ReadAsStreamAsync();
HttpResponseMessage message = new HttpResponseMessage(HttpStatusCode.OK);
message.Content = new StreamContent(stream);
message.Content.Headers.ContentLength = stream.Length;
message.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return message;
}
EDIT
Ok so this actually sends back the PDF when I write the proxy like this
[AllowAnonymous]
[HttpGet("openPDF")]
public async Task<FileStreamResult> OpenPDF([FromQuery] string url)
{
var fileStream = new MemoryStream();
var _httpClient = _httpClientFactory.CreateClient();
var file = await _httpClient.GetStreamAsync(url).ConfigureAwait(false);
await file.CopyToAsync(fileStream);
fileStream.Position = 0;
return File(fileStream, "application/pdf", "filename.pdf");
}
The problem is I want to update the content-disposition to inline so I can force this to open in the browser instead of downloading.So I decided to take the filestream and injecting that in the httpResponseMessage.content instead but that still didn't work. It would continue to send me a json file
[AllowAnonymous]
[HttpGet("openPDF")]
public async Task<HttpResponseMessage> OpenPDF([FromQuery] string url)
{
var fileStream = new MemoryStream();
var _httpClient = _httpClientFactory.CreateClient();
var file = await _httpClient.GetStreamAsync(url).ConfigureAwait(false);
await file.CopyToAsync(fileStream);
fileStream.Position = 0;
HttpResponseMessage message = new HttpResponseMessage(HttpStatusCode.OK);
message.Content = new StreamContent(fileStream);
message.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return message;
}
To be honest, I thought defining the content-type should suffice but guess not
This is pretty straight forward for .NET 6... suspect it should be roughly the same for .NET 4x... This uses the NuGet package Azure.Storage.Blobs
https://github.com/Azure/azure-sdk-for-net/blob/Azure.Storage.Blobs_12.13.1/sdk/storage/Azure.Storage.Blobs/README.md
[HttpGet("stream")]
public async Task GetBlobAsync()
{
var url = new Uri("https://path.to.blob.content/xxx");
var blobClient = new BlobClient(url);
Response.Headers.Add("Content-Type", "application/pdf");
Response.Headers.Add("Content-Disposition", #"attachment;filename=""intended file name.pdf""");
await blobClient.DownloadToAsync(Response.Body);
}
for .NET 4x.
try to add:
result.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("inline")
{
FileName = "filename.pdf"
};
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);
}
}
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);
}
The below code is working perfect. It serves the specified image.
public HttpResponseMessage Get(string id)
{
string fileName = string.Format("{0}.png", id);
FileStream fileStream = File.Open(System.Web.Hosting.HostingEnvironment.MapPath("~/Images/" + fileName), FileMode.Open);
HttpResponseMessage response = new HttpResponseMessage { Content = new StreamContent(fileStream) };
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpg");
response.Content.Headers.ContentLength = fileStream.Length;
return response;
}
Just to release the resource that I acquired to read the image file I have modified the code as follows.
public HttpResponseMessage Get(string id)
{
string fileName = string.Format("{0}.png", id);
using (FileStream fileStream = File.Open(System.Web.Hosting.HostingEnvironment.MapPath("~/Images/" + fileName), FileMode.Open))
{
HttpResponseMessage response = new HttpResponseMessage { Content = new StreamContent(fileStream) };
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpg");
response.Content.Headers.ContentLength = fileStream.Length;
return response;
}
}
I am getting the error "Error while copying content to a stream". Yes. I am closing the resource before it is streamed.
But the question is how to serve the image and still close the unhandled resource?
Asp.Net Web API 2 and above.
Thank you for your thoughts.
You don't need to worry about releasing FileStream object. It will closed by lower layers of Web API once response is complete. Code mentioned in your first snippet is fine.
public HttpResponseMessage getLogoPath(int ID)
{
String urlsubfix = dataManager.getMobileLogoPath(ID);
String urlToReturn = PictureController.urlprefix +urlsubfix;
var response = Request.CreateResponse(HttpStatusCode.Redirect);
response.Headers.Location = new Uri(urlToReturn);
return response;
}
I want to have one of the API call to return an image, how I am accomplishing that is to redirect to another link that has the image, for example :
http://steve.files.wordpress.com/2006/03/Matrix%20tut%202.jpg
I am trying to use PostMan to test this and it gives me back a broken image. I tried derping around and still couldn't find a solution.
-----Edit part of the code that needs this
public HttpResponseMessage GetCustomerBarCodeLogo(String ID)
{
Barcode BC = new Barcode();
Image img =BC.Encode(TYPE.CODE128, "123456789");
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
ImageConverter imageConverter = new ImageConverter();
byte[] resourceByteArray = (byte[])imageConverter.ConvertTo(img, typeof(byte[]));
MemoryStream dataStream = new MemoryStream(resourceByteArray);
result.Content = new StreamContent(dataStream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
return result;
}
This returns a broken image.
------Newest Update
I sort of found out the problem. What happens is that there is a problem with SSL basic authentication. What happens is when the first time the client wants to pass in a request, the authentication was set correctly. However, when it tries to get an image which is another request after that is triggered by internal code, that request does not have autherizationHeader and it is not authenticated. I don't know where is the 2nd event triggered so I don't know how to manually set that header.
You cannot redirect to response an image in this url, your caller would be able to change the location.
First solution, try using directly the image result for web api, for sample:
public HttpResponseMessage getLogoPath(int id)
{
string pathImage = // a way to get the imagem path..
// create response
HttpResponseMessage response = new HttpResponseMessage();
// set the content (image)
response.Content = new StreamContent(new FileStream(pathImage));
// set the content type for the respective image
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png"); // or jpg, gif..
return response;
}
Or use Moved Status Code, for smaple:
public HttpResponseMessage getLogoPath(int ID)
{
String urlsubfix = dataManager.getMobileLogoPath(ID);
String urlToReturn = PictureController.urlprefix + urlsubfix;
var response = Request.CreateResponse(HttpStatusCode.Moved);
response.Headers.Location = new Uri(urlToReturn);
return response;
}
Here is an alternate way that might work for you. This is the close the the technique I use.
public HttpResponseMessage GetCustomerBarCodeLogo(String ID)
{
Barcode BC = new Barcode();
Image img =BC.Encode(TYPE.CODE128, "123456789");
var dataStream = new MemoryStream();
img.Save(dataStream, ImageFormat.Png);
dataStream.Position = 0;
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(dataStream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
return result;
}
You can use the FileResult for example
public FileResult GetLogo(string imageName)
{
return File(Server.MapPath("~/App_Data/Images/") + imageName, "image");
}
In this case the File function takes the file path and content type and returns a file response.