Display PDF file from C# to Angular2 view - c#

I'm trying to display a PDF that was previously uploaded into the server. The PDF resides inside the App_Data folder. I want to fetch it using C# Web API 2 and display it in my Angular 2 frontend view.
C# code:
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.BadRequest);
string filename = "somefilename.pdf";
byte[] buffer = new byte[0];
MemoryStream memStream = new MemoryStream();
if (filename != "") {
PdfReader reader = new PdfReader(Path.Combine(HttpContext.Current.Request.PhysicalApplicationPath) + "/App_Data/Uploads/PDFs/" + filename);
PdfStamper stamper = new PdfStamper(reader, memStream);
response = Request.CreateResponse(HttpStatusCode.OK);
buffer = memStream.ToArray();
response.Content = new StreamContent(new MemoryStream(buffer));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response.Content.Headers.ContentLength = buffer.Length;
ContentDispositionHeaderValue contentDisposition = null;
if (ContentDispositionHeaderValue.TryParse("inline; filename=" + filename, out contentDisposition))
{
response.Content.Headers.ContentDisposition = contentDisposition;
}
}
return response;
Angular 2 code:
this.documentsService.getFile()
.subscribe((response: any) => {
let file = new Blob([response], { type: 'application/pdf' });
let url = URL.createObjectURL(file);
window.open(url);
});
I think my Angular code is wrong. But nevertheless, my first goal here is to fetch it from the MVC side. Right now the file gets downloaded and it's corrupted or there's not fetch correctly. It always give me a 15bytes size PDF file, so I know there's something wrong. I'm using iTextSharp in my C# backend.
Thanks in advance!

From my comment (providing an answer is easier for code):
if (filename != "") {
var fs = System.IO.File.OpenRead(filename);
_myDisposable = fs; // see further down in this answer.
var response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StreamContent(fs);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return response;
}
return response;
Edit: The code I posted above works for me. The only problem is disposing of the stream. The best way to probably do that is by creating a private IDisposable member on your controller class, and then adding a dispose override, sort of like this:
private IDisposable _myDisposable;
public override void Dispose(bool disposing)
{
if (disposing && _myDisposable != null)
_myDisposable.Dispose();
}
Please note that this assumes ASP.NET is done with the request (which seems reasonable, because it's disposing of your controller), which should be correct.

Related

Stuck generating + sending .xlsx file from ASP.NET Web API backend to Vue.js frontend

I am trying to generate an excel file in my ASP.NET Web API backend, and send it to my Vue.js front end for download.
The API request is being made by calling getQueryResults:
const apiClient = axios.create({
baseURL: process.env.NODE_ENV == "production" ? PROD_URL : TEST_URL,
withCredentials: true, // This is the default
headers: {
Accept: "application/json",
"Content-Type": "application/json"
}
});
getQueryResults(table, filters, selected, clientId, fundId, periodId, pageNumber, pageSize, exportExcel){
return apiClient.post(`queryResults`, {
responseType: 'blob',
table,
filters,
selected,
clientId,
fundId,
periodId,
pageNumber,
pageSize,
exportExcel
});
}
In the backend, the excel file is generated inside of QueryResultsExport.cs (EPPlus is version 4.1.0):
public static MemoryStream exportToExcel(IQueryable<object> itemsToExport)
{
if (itemsToExport.Count() == 0)
return null;
ExcelPackage excel = new ExcelPackage();
ExcelWorksheet workSheet = excel.Workbook.Worksheets.Add("Query Results");
DataTable dataTable = toDataTable(itemsToExport.ToList());
workSheet.Cells["A1"].LoadFromDataTable(dataTable, true);
/*
string path = #"C:\Users\asdfq321\Downloads\test11.xlsx";
Stream stream = File.Create(path);
excel.SaveAs(stream);
stream.Close();
return null;
*/
MemoryStream ms = new MemoryStream(excel.GetAsByteArray());
excel.Dispose();
return ms;
}
You can see i commented out some code that saves the excel file locally as an .xlsx file, instead of returning a memorystream. I did this to ensure the problem was not in the excel generation. The file saved locally on the server appears to be correct, and it has a size of 3442 Bytes (this is relevant later on).
Next, the memorystream is sent back to the client:
[HttpPost]
[Route("queryResults")]
public HttpResponseMessage GetQueryResults([FromBody]Dictionary<string, object> queryParams)
{
// continued from above...
MemoryStream ms = QueryResultsExport.exportToExcel(queryItems);
HttpResponseMessage httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK);
httpResponseMessage.Content = new StreamContent(ms);
httpResponseMessage.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
httpResponseMessage.Content.Headers.ContentDisposition.FileName = "asdfq.xlsx";
httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
return httpResponseMessage;
}
Finally, on the Vue front end, the response is handled:
.then(result => {
var myBlob = new Blob([result.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'})
const url = window.URL.createObjectURL(myBlob);
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'asdfq.xlsx'); //or any other extension
document.body.appendChild(link);
link.click();
})
The result is that a popup box appears prompting me to download an excel file. However, the file cannot be read, and when it is opened the message appears "We found a problem with some content in asdfq.xlsx. Do you want us to try to recover as much as we can? If you trust the source of this workbook, click Yes." When I click yes, I get "Excel cannot open the file asdfq.xlsx because the file format or file extension is not valid. Verify that the file has not been corrupted and that the file extension matches the format of the file."
When I look at the response in the browser dev tools Network tab, I see that the response has Content-Length: 3442, which seems to be correct: this matches the excel file I successfully saved on the server earlier. However, the excel file that ends up being downloaded has a size of 5635 bytes.
Here is a picture of the response headers:
Here is a picture of Console.log(result):
I have tried various things like changing the responseType, the type passed into the blob constructor, the header ContentType, the Accept header in the request, how the memory stream is added to the response, etc, but I have not had any luck getting this to work: the result is always the same; a corrupted excel file with size of 5635 bytes instead of the expected 3442 bytes. Any help would be very much appreciated; thanks!
edit: I noticed in the code snippets I pasted, I have
httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
In the back end, but in the front end I have
var myBlob = new Blob([result.data], {type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'})
I did try setting these both to "application/octet-stream", or both to "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", but it makes no difference.
I also tried different ways of generating the response:
//attempt 1
MemoryStream ms = QueryResultsExport.exportToExcel(queryItems);
HttpResponseMessage httpResponseMessage = Request.CreateResponse(HttpStatusCode.OK);
httpResponseMessage.Content = new StreamContent(ms);
httpResponseMessage.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
httpResponseMessage.Content.Headers.ContentDisposition.FileName = "asdfq.xlsx";
httpResponseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
// ms.Close();
return httpResponseMessage;
//attempt 2
MemoryStream ms = QueryResultsExport.exportToExcel(queryItems);
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(ms.ToArray())
};
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "asdfq.xlsx";
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
return result;
// atempt 3
MemoryStream ms = QueryResultsExport.exportToExcel(queryItems);
ms.Position = 0;
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(ms.GetBuffer())
};
result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment"){FileName = "export.xlsx"};
string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
result.Content.Headers.ContentType = new MediaTypeHeaderValue(contentType);
result.Content.Headers.Add("content-length", ms.Length.ToString());
return result;
Finally, in QueryResultsExport.exportToExcel, I also tried
var ms = new MemoryStream();
excel.SaveAs(ms);
return ms;
But none of this makes any difference.
I was able to get it working by sending the excel file as StringContent instead of ByteArrayContent, as seen here:
How to download ByteArrayContent of HttpResponseMessage as zip
MemoryStream ms = QueryResultsExport.exportToExcel(queryItems);
string base64String = System.Convert.ToBase64String(ms.ToArray(), 0, ms.ToArray().Length);
var result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(base64String)
};
return result;
.then(result => {
const link = document.createElement('a');
link.href = 'data:application/octet-stream;charset=utf-8;base64,' + result.data;
link.target = '_blank';
link.download = 'asdfq.xlsx';
link.click();
})
Assigning a responseType in the api request doesn't seem necessary. Neither does setting a Content.Headers.ContentDisposition or Content.Headers.ContentType.

When creating a Zip file in memory, why do I have to parse the MemoryStream for the Zip to be created correctly?

I've looked at other questions on here but nobody answers my question as to why I can't use the already existing MemoryStream that exists to create the zip.
Here is a working API method to get a zipped folder containing files. The files already exist on the server and the method simply looks up there location and, all in memory, retrieves all the files and sends the user a HttpResponMessage object with the Zipped folder containing all the files. There is one line of code below that doesn't seem to make sense however. I have to parse the MemoryStream to a byte array then back to a MemoryStream in order for the Zip to be created and sent back correctly. This seems wrong, but I don't know how to correct it. (See below "//Works:" and "//Does Not work:")
public HttpResponseMessage GetEvalByCompany([FromUri]Guid id, [FromUri] int year)
{
try
{
string companyName = _portalDB.Companies.FirstOrDefault(c => c.Id == id).FirmName;
//Get all evaluation file paths for a given company for a given year
var files = _evaluationDB.Evaluations.Where(j => j.CompanyId == id).Select(j => #"C:\Path\To\File" + j.RelativePath.Replace("~", #"").Replace(#"/", #"\")).Distinct().ToList<string>();
using (var outStream = new MemoryStream())
{
using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
{
foreach (var record in files)
{
var fileInArchive = archive.CreateEntryFromFile(record, Path.GetFileName(record), CompressionLevel.Optimal);
}
}
// Create a response
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
//Works:
response.Content = new StreamContent(new MemoryStream(outStream.ToArray())); //Why does this need to happen?
//Does Not work:
//response.Content = new StreamContent(outStream); //Why doesn't this work?
// Add appropriate headers to make browser recognize response as a download
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "Evaluations for Company - " + companyName + ".zip";
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/zip");
return response;
}
}
catch (Exception ex)
{
return ErrorHandler.HandleException(ex, Request);
}
}
Based on the answers I received I was able to fix the code so it doesn't have to parse the stream unnecessarily. Here's the updated code for future devs looking for the solution simply. Removing the using doesn't seem to cause any GC issues either. I found a link to explain that a bit better as well. (MemoryStream.Close() or MemoryStream.Dispose())
public HttpResponseMessage GetEvalByCompany([FromUri]Guid id, [FromUri] int year)
{
try
{
string companyName = _portalDB.Companies.FirstOrDefault(c => c.Id == id).FirmName;
//Get all evaluation file paths for a given company for a given year
var files = _evaluationDB.Evaluations.Where(j => j.CompanyId == id).Select(j => #"C:\Path\To\File" + j.RelativePath.Replace("~", #"").Replace(#"/", #"\")).Distinct().ToList<string>();
var outStream = new MemoryStream();
using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
{
foreach (var record in files)
{
var fileInArchive = archive.CreateEntryFromFile(record, Path.GetFileName(record), CompressionLevel.Optimal);
}
}
// Create a response
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
//Updated code
outStream.Seek(0, SeekOrigin.Begin);
response.Content = new StreamContent(outStream); //works now because outStream isn't in a using block
// Add appropriate headers to make browser recognize response as a download
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "Evaluations for Company - " + companyName + ".zip";
response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/zip");
return response;
}
catch (Exception ex)
{
return ErrorHandler.HandleException(ex, Request);
}
}
Remove
using (var outStream = new MemoryStream()),
leave instead only:
var outStream = new MemoryStream();
Then later :
outStream.Seek(0, SeekOrigin.Begin)
response.Content = new StreamContent(outStream);
The problem here is that your original MemoryStream is getting disposed before it is used. StreamContent is keeping a reference to an object that is disposed. You need to remove the using block for outStream and somehow arrange to dispose of it later.

Download PDF File from API Using C#

I am creating a console application that
Connects to a vendor API to pull voucher numbers for submitted expenses between two dates and
Downloads a PDF copy of receipts submitted with the expense
The first part, I have working fine. I am able to connect to the Vendor API and parse out the returned XML to create an array of voucher numbers (needed to get the PDF images) using the following code:
static async Task RunAsyncCR()
{
using (var client = new HttpClient())
{
var values = new Dictionary<string, string>
{
{"un","SomeUser"},
{"pw","SomePassword"},
{"method","getVoucherInvoices"},
{"fromDate","05/30/2016"},
{"toDate", "06/13/2016"}
};
var content = new FormUrlEncodedContent(values);
Console.WriteLine("Connecting...");
var response = await client.PostAsync("https://www.chromeriver.com/receipts/doit", content);
Console.WriteLine("Connected...");
var responseString = await response.Content.ReadAsStringAsync();
char[] DelimiterChars = {'<'};
String[] xmlReturn = responseString.Split(DelimiterChars);
string[] VoucherNumber = new string[500];
int i = 0;
foreach (string s in xmlReturn)
{
if (s.Contains("voucherInvoice>") && s != "/voucherInvoice>\n ")
{
VoucherNumber[i] = s.Substring(15, 16);
i++;
}
}
Array.Resize(ref VoucherNumber, i);
Yes, there is likely a better way of doing this, but it works and returns the values I am expecting.
Now, what I am having trouble with, is when I connect back to the API to retrieve the file, I cannot seem to be able to download the file to a specified file path.
I can connect back to the API using
i = 0;
foreach (string x in VoucherNumber)
{
Console.WriteLine("Get receipt: " + x);
var NewValues = new Dictionary<string, string>
{
{"un","SomeUser"},
{"pw","SomePassword"},
{"method","getReceiptsWithCoverPage"},
{"voucherInvoiceForPdf", VoucherNumber[i]}
};
var NewContent = new FormUrlEncodedContent(NewValues);
var NewResponse = await client.PostAsync("https://www.chromeriver.com/receipts/doit", NewContent);
string NewResponseString = await NewResponse.Content.ReadAsStringAsync();
But I cannot seem to write the response to a valid file (PDF)
Here is a screen shot of my Autos window as I step through the code, where I would need to download the file:
My question is, from this point, how do I go about saving the file to my system?
I have tried to take the encoded response I get from doing Console.WriteLine(NewResponseString); and write it to a file using the System.IO.File.WriteAllLines() method, using a specified filepath/name, but this results in a blank file. I have also spent some time researching the depths of Google/Stackoverflow, but do not understand how to implement the results I find.
Any and all help would be greatly appreciated.
So I think you need help with Streams. The returned HttpContent is actually a System.Net.Http.StreamContent instance which shows that you are getting content back. Its just a matter of getting the Stream (content) from that instance and saving that to a file.
var NewResponse = await client.PostAsync("https://www.chromeriver.com/receipts/doit", NewContent);
System.Net.Http.HttpContent content = NewResponse.Content; // actually a System.Net.Http.StreamContent instance but you do not need to cast as the actual type does not matter in this case
using(var file = System.IO.File.Create("somePathHere.pdf")){ // create a new file to write to
var contentStream = await content.ReadAsStreamAsync(); // get the actual content stream
await contentStream.CopyToAsync(file); // copy that stream to the file stream
}
I respectfully recommend that you do a little reading on how Streams work. This is a common construct in many languages that you will probably have to deal with again in the near future.
First of all, are you sure there is a file to begin with? May I suggest using the open source library PdfSharp. I personally use it myself and it works great. As far as downloading the file, maybe this may help you...
Download Synchronously
using System.Net;
WebClient webClient = new WebClient();
webClient.DownloadFile("http://example.com/myfile.txt", #"c:\\myfile.txt");
http://www.csharp-examples.net/download-files/
At first Create StreamReader from NewResponse
Stream receiveStream = NewResponse.GetResponseStream ();
StreamReader readStream = new StreamReader (receiveStream, Encoding.UTF8);
Then Define a StremaWriter to write into a file.
using (var writer = new StreamWriter(#"C:\MyNewFile.pdf", append: false))
{
writer.Write(readStream.ReadToEnd());
}
Alternative Approach is
var httpContent = NewResponse.Content;
using(var newFile = System.IO.File.Create(#"C:\MyNewFile.pdf"))
{
var stream = await httpContent.ReadAsStreamAsync();
await stream.CopyToAsync(newFile);
}
Here is what I did, did not find any other solution that satisfied my situation:
using (var client = new System.Net.Http.HttpClient())
{
client.DefaultRequestHeaders.Add("Authorization", "someapikey");
client.BaseAddress = new Uri("https://someurl.com");
byte[] bytes = client.GetByteArrayAsync(client.BaseAddress).ConfigureAwait(false).GetAwaiter().GetResult();
string pdfFilePath = #"c:\somepath"
System.IO.File.WriteAllBytes(pdfFilePath, bytes);
//Note that below is only to open PDF in standard viewer, not necessary
var process = new System.Diagnostics.Process();
var startInfo = new System.Diagnostics.ProcessStartInfo()
{
FileName=pdfFilePath,
WorkingDirectory = System.IO.Path.GetDirectoryName(pdfFilePath),
UseShellExecute = true
}
process.StartInfo = startInfo;
process.Start();
}
Use this code for download a pdf from the API. It will convert the string data to bytes and provide you the necessary solution.
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(URL);
request.ContentType = "application/pdf;charset=UTF-8";
request.Method = "GET";
using(HttpWebResponse response = (HttpWebResponse) request.GetResponse()) {
BinaryReader bin = new BinaryReader(response.GetResponseStream());
byte[] buffer = bin.ReadBytes((Int32) response.ContentLength);
Response.Buffer = true;
Response.Charset = "";
Response.AppendHeader("Content-Disposition", "attachment; filename=+ filename);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.ContentType = "application/pdf";
Response.BinaryWrite(buffer);
Response.Flush();
Response.End();
}

download file from web server in asp.net c# to client's pc

I am trying to download a file from the server to a folder that the client chooses onto their machine. But I keep getting the error could not find part of the path
For example the DownloadLocation could be C:/myfolder
Code:
FileName = comp.DownloadLocation + "/" + "/purchase" + ".csv";
regularfilename = "purchase.csv";
byte[] buffer;
using (FileStream fileStream = new FileStream(FileName, FileMode.Open))
{
int fileSize = (int)fileStream.Length;
buffer = new byte[fileSize];
fileStream.Read(buffer, 0, (int)fileSize);
}
Response.Clear();
Response.Buffer = true;
Response.BufferOutput = true;
Response.ContentType = "application/x-download";
Response.AddHeader("Content-Disposition", "attachment; filename=" + regularfilename);
Response.CacheControl = "public";
Response.OutputStream.Write(buffer, 0, buffer.Length);
Response.Flush();
Response.Clear();
Response.End();
Possibly not the answer however this is something you should definitely check:
FileName = comp.DownloadLocation + "/" + "/purchase" + ".csv";
You probably want to remove the / before purchase or drop the + "/" + completely as that's going to build up a path in the format:
"somepath//purchase.csv"
May well be casuing your issue. See if it makes a difference.
If you need a client app to check the Web API server to see if the server's version of a file is newer than the version the client has, you can set up the server to do so by performing these steps:
Add the appropriate method to a Repository Interface, such as:
HttpResponseMessage GetCervezaBeberUpdate(string clientVersion);
Add this to the corresponding Controller class (where the Controller name is "HenryFieldingController"):
[Route("api/HenryFielding/GetUpdatedCervezaBeber")]
public HttpResponseMessage GetUpdate(string clientVersion)
{
return _tomJonesRepository.GetCervezaBeberUpdate(clientVersion);
}
Add the appropriate method to the concrete Repository class, such as:
public HttpResponseMessage GetCervezaBeberUpdate(string clientVersion)
{
var binaryFilePath = HostingEnvironment.MapPath(#"~\App_Data\CervezaBeber.exe");
FileVersionInfo currentVersion = FileVersionInfo.GetVersionInfo(binaryFilePath);
if (!ServerFileIsNewer(clientVersion, currentVersion))
{
result = new HttpResponseMessage(HttpStatusCode.NoContent);
}
else
{
var stream = new FileStream(binaryFilePath, FileMode.Open);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
}
return result;
}
Also add the method in that Repository class that GetCervezaBeberUpdate() calls:
private bool ServerFileIsNewer(string clientFileVersion, FileVersionInfo serverFile)
{
Version client = new Version(clientFileVersion);
Version server = new Version(string.Format("{0}.{1}.{2}.{3}", serverFile.FileMajorPart, serverFile.FileMinorPart, serverFile.FileBuildPart, serverFile.FilePrivatePart));
return server > client;
}
Now the client can call this by passing a URI like this to the server:
http://<servername>:<portnumber>/api/
<controllername>?clientVersion=<clientversionquad>
Or, for a more literal example, in the event your server's name is "Platypus", the port to use is 4242, the Controller is named HenryFieldingController, and the version of the file the client currently has is 3.1.4.1:
http://Platypus:4242/api/HenryFielding?clientVersion=3.1.4.1
As a free-as-in-beer (you/I wish!) premium, here's some code the client can use to save the server's response to a file (passing this a URI such as shown above):
private void DownloadTheFile(string uri)
{
var outputFileName = "Platypus.exe";
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
var webResponse = (HttpWebResponse)webRequest.GetResponse();
string statusCode = webResponse.StatusCode.ToString();
// From here on (including the CopyStream() method) derived from Jon Skeet's
// answer at http://stackoverflow.com/questions/411592/how-do-i-save-a-stream-to-a-file
if (statusCode == "NoContent")
{
MessageBox.Show("You already have the newest available version.");
}
else
{
var responseStream = webResponse.GetResponseStream();
using (Stream file = File.Create(outputFileName))
{
CopyStream(responseStream, file);
MessageBox.Show(string.Format("New version downloaded to {0}", outputFileName));
}
}
}
public static void CopyStream(Stream input, Stream output)
{
byte[] buffer = new byte[8 * 1024];
int len;
while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, len);
}
}

Issue returning images over web api

I am having a weird issue returning an image via web api, I do this in several places in my application without fail but this one is causing me issues, any help would be greatly appreciates.
This works
Bitmap bitmap = getImage();
MemoryStream bitmapStream = new MemoryStream();
bitmap.Save("C:\\test.png", System.Drawing.Imaging.ImageFormat.Png);
if (bitmap != null)
{
if (Request.Headers.IfModifiedSince.HasValue)
{
// The file has not been modified since the browser cached it.
return new HttpResponseMessage(HttpStatusCode.NotModified);
}
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(new FileStream("C:\\test.png", FileMode.Open));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
return response;
}
else
{
return new HttpResponseMessage(HttpStatusCode.NotFound);
}
while this does not
Bitmap bitmap = getImage();
MemoryStream bitmapStream = new MemoryStream();
bitmap.Save(bitmapStream, System.Drawing.Imaging.ImageFormat.Png);
if (bitmap != null)
{
if (Request.Headers.IfModifiedSince.HasValue)
{
// The file has not been modified since the browser cached it.
return new HttpResponseMessage(HttpStatusCode.NotModified);
}
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(bitmapStream);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/png");
return response;
}
else
{
return new HttpResponseMessage(HttpStatusCode.NotFound);
}
I really need to do this in memory and not save a temp file to drive, but for some reason when I do it in memory the result is an empty file 0 bytes, I do try to set the content length manually but then the file doesnt download at all.
You would need to reset the position of the stream after the save happens.
bitmapStream.Position = 0;

Categories

Resources