instead of downloading Open pdf in browser(using itext) mvc [duplicate] - c#

This question already has an answer here:
PDF downloading directly in Google Chrome -- how to display in browser window instead? [closed]
(1 answer)
Closed 5 years ago.
I am able to download and store the pdf document that is being generated but instead of downloading I want to open it in browser.
I have something like this
MemoryStream os = new MemoryStream();
PdfWriter writer = new PdfWriter(os);
var pdfDocument = new PdfDocument(writer);
using (var document = new Document(pdfDocument))
{
//I am adding different sections here
}
var response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new ByteArrayContent(os.ToArray())
};
response.Content.Headers.Add("Content-Type", "application/pdf");
response.Headers.Add("Content-disposition", "attachment;filename=" + "testPDF.pdf");
return response;
The response is further being sent to controller and there it is being downloaded but I want to open in new browser.
For me, "Content-disposition", "attachment;filename" is not working.
My return value is being passed on the controller further where I am storing in blob and continues to download.
public async Task<IActionResult> GenerateDocument(int id)
{
var result = await _applicationService.GenerateDocument(id);
var blobResult = await _applicationService.SaveDocument(id, result.ResponseObject);
IActionResult OnSuccess() =>
new RedirectResult(blobResult.ResponseObject.URI, true);
return HandleResult(OnSuccess, blobResult.Status);
}

You would want to use inline for the content disposition to let the browser know to display it
//...code removed for brevity
var buffer = os.ToArray();
var contentLength = buffer.Length;
var statuscode = HttpStatusCode.OK;
var response = Request.CreateResponse(statuscode);
response.Content = new ByteArrayContent(buffer);
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response.Content.Headers.ContentLength = contentLength;
ContentDispositionHeaderValue contentDisposition = null;
if (ContentDispositionHeaderValue.TryParse("inline; filename=" + "testPDF.pdf", out contentDisposition)) {
response.Content.Headers.ContentDisposition = contentDisposition;
}
return response;

Related

How to return PDF content from another HttpResponseMessage to the browser?

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

Reading Multipart Data from Xamarin

We have a requirement of sending the jpeg files of a given directory to a Xamarin App.
Following is the code in the Web API.
public HttpResponseMessage DownloadMutipleFiles()
{
name = "DirectoryName";
var content = new MultipartContent();
var ids = new List<int> { 1,2};
var objectContent = new ObjectContent<List<int>>(ids, new System.Net.Http.Formatting.JsonMediaTypeFormatter());
content.Add(objectContent);
var file1Content = new StreamContent(new FileStream(#"D:\Photos\" + name+"\\"+ "BL1408037_20191031124058_0.jpg", FileMode.Open));
file1Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("image/jpeg");
content.Add(file1Content);
var file2Content = new StreamContent(new FileStream(#"D:\Photos\" + name + "\\" + "BL1408037_20191031124058_1.jpg", FileMode.Open));
file2Content.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse("image/jpeg");
content.Add(file2Content);
var response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = content;
return response;
}
Can some one help out with how to read from Xamarin app? Thanks in advance
This is the function I was able to use to send an image as a multi part data file! I just took the byte array given to me by the Xamarin Essentials image picker and passed it into this function:
public async Task SubmitImage(byte[] image, string imageName)
{
using (var client = new HttpClient())
{
string url = $"..."; // URL goes here
var token = Preferences.Get("AccessToken", "");
client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var stream = new MemoryStream(image);
var content = new StreamContent(stream);
//Without a name we can't actually put the file in IFormFile. We need the equivalent
//"name" value to be "file" (used if you upload via an <input> tag). We could call it
//anything but file is simple
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
FileName = imageName,
Name = "file"
};
content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
var multipartContent = new MultipartFormDataContent();
multipartContent.Add(content);
var result = await client.PostAsync(url, multipartContent);
}
}
You can test this using a console application as well and just send over a picture from your computer, instead of doing this through the app

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

Serve the image - Close the image resource

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.

Categories

Resources