Prevent IDM from downloading automatically in web api - c#

I have a web api method that returns an HttpResponseMessage containing a PDF file. The method looks something like this:
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StreamContent(new FileStream(path, FileMode.Open, FileAccess.Read));
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = fileName;
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return response;
When I call this api from client (which is written in angularJS), the Internet Download Manager automatically catches the PDF file and wants to download it. And because I have a security plan for my project, the IDM automatically requests username and password.
Does anyone have an idea about how I'm supposed to programmatically stop IDM from catching the PDF file?
Update: Here's my angularJS code:
$http.post(url, { transactionId: txId }
, {responseType: 'arraybuffer'})
.success(function (response) {
var reader = new FileReader();
var file = new Blob([response.data], {type: 'application/pdf'});
reader.onload = function (e) {
var printElem = angular.element('#printPdfLink');
printElem.attr('target', '_blank');
printElem.attr('href', reader.result);
printElem.attr('ng-click', '');
};
reader.readAsDataURL(file);
})
.error(function (error) {});

Change the mime type to application/octet-stream as a way to work around your problem. Make sure that the file name includes a proper file extension so that it can be recognized by the client system once downloaded.
Another issue is the attachment disposition of the content which typically forces it to save it as a file download. Change it to inline so that the client can consume it without IDM trying to download it as an attachment.
FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read);
StreamContent content new StreamContent(stream);
content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline");
content.Headers.ContentDisposition.FileName = fileName;
content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = content;
return response;

I have try to use HttpResponseMessage.
If I use ContentDisposition is inline then response break the file. If use attachment then IDM can detect it.
At the end of the day, I found Accept-Ranges header can make download without IDM but it not valid in HttpResponseMessage.
You can try out my code below to make download file without IDM:
[HttpGet]
[Route("~/download/{filename}")]
public void Download(string filename)
{
// TODO lookup file path by {filename}
// If you want to have "." in {filename} you need enable in webconfig
string filePath = "<path>"; // your file path here
byte[] fileBytes = File.ReadAllBytes(filePath);
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.AddHeader("Accept-Ranges", "bytes");
HttpContext.Current.Response.ContentType = "application/octet-stream";
HttpContext.Current.Response.AddHeader("ContentDisposition", "attachment, filename=" + filename);
HttpContext.Current.Response.BinaryWrite(fileBytes);
HttpContext.Current.Response.End();
}
Note: filename parameter serve for download file name so you can config in webconfig if you want to have file extension (disabled by default).

Related

How to save the response in the Postman same as the name I mentioned it?

This piece of code will put all the data(string) as an XML format in the Postman. But when I try to save the response in the Postman so, it will save as response.xml, which I don't want. I want that Postman will save my XML content in the form of filename.xml.
So, how should I proceed with? I have to google it and found that something like attachment, content-type, and all must be used. But, didn't solve my case. Please help with your suggestion.
For simplicity, I have reduced the code. Here, graphics is string datatype.
public ActionResult GetXML()
{
string filename = "Demo";
return Content(graphics, "application/xml");
}
You need to set Content-Disposition header so the that browser prompts for saving response.
You can do that by using following approach.
public IActionResult Getxml()
{
var xmlData =
"<records><record><Name>Camacho, Sydnee Q.</Name><Id>1</Id><Age>19</Age><City>Podolsk</City></record><record><Name>Bowman, Lester V.</Name><Id>2</Id><Age>21</Age><City>Padang</City></record></records>";
//sampleFile.xml can be replaced by any filename of your choice.
var fileName = "sampleFile.xml";
Response.Headers.Add("Content-Disposition", $"attachment; filename={fileName}");
return Content(xmlData, "application/xml", Encoding.UTF8);
}
With this change when this URL is browsed in the browser it will prompt save dialog with sampleFile.xml populated as filename.
Also when you save the response from postman it will show sampleFile.xml populated as file name in the dialog.
I hope this will help you solve your issue.
I would suggest to use the FileContentResult for a file download.
public ActionResult GetXML()
{
var fileName = "Demo.xml";
var xml = "...";
return new FileContentResult(Encoding.UTF8.GetBytes(xml), "application/xml; charset=utf-8")
{
FileDownloadName = fileName,
};
}
You need to set the response headers so that the download client automatically treats the content as a "file", the key is the ContentDisposition header, this is how we pass the filename back.
public HttpResponseMessage GetXMLFile()
{
string filename = "Demo";
var byteArray = System.Text.Encoding.UTF8.GetBytes(graphics);
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StreamContent(new MemoryStream(byteArray), byteArray.Length)
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") //attachment will force download
{
FileName = filename
};
return result;
}

Downloading a .doc extension file saved in stream memory - returned from web service api (.asmx file) to angular service

I have a web service (.asmx file extension), which creates a Document (Aspose.Words) which I save to MemoryStream.
I would like the user to download the file on click - without having to save the actual file anywhere but to the users computer when he downloads.
I am struggling with this for quite a while...
even if i manage to download the file - the content is not correct.
This is my angular code:
const headers = new HttpHeaders({ 'Content-Type': 'application/json' });
Generate() {
this.http.get(
`${this.environment.Url}Generate`, {
headers: headers,
responseType: 'arraybuffer'
}
).subscribe((res: any) => {
this.downLoadFile(res, 'application/msword');
}
);
}
downLoadFile(data: any, type: string) {
let blob = new Blob([data], { type: type});
let url = window.URL.createObjectURL(blob);
let pwa = window.open(url);
if (!pwa || pwa.closed || typeof pwa.closed === 'undefined') {
alert( 'Please disable your Pop-up blocker and try again.');
}
}
And this is what i did in the web service:
public async Task<Stream> Generate() {
Document doc = _Generate(profileToCV);
MemoryStream dstStream = new MemoryStream();
doc.Save(dstStream, SaveFormat.Docx);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(dstStream);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "foo";
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/msword");
response.Content.Headers.ContentLength = dstStream.GetBuffer().Length;
return await response.Content.ReadAsStreamAsync();
}
I tried alot of different variations.
like changing the responseType returned to 'blob' or 'blob' as 'json',
or returning the HttpResponseMessage.
nothing worked as expected.
I can't seem to extract the content saved in what is returned to client properly in file.
so - Help! ... Thanks in advance!
Just create a link element and fire click event,
this.blob = new Blob([data], {type: 'application/pdf'}); // your file format
var downloadURL = window.URL.createObjectURL(data);
var link = document.createElement('a');
link.href = downloadURL;
link.download = "help.pdf";
link.click();

Failed to load PDF document in web api

I am getting error while downloading and opening pdf files as
Failed to load PDF document
. But when i tried to download txt file it gets download success fully. I need to this ajax request to be as POST method, So after searching in internet i found this code.
$.ajax({
type: "POST",
url: url,
cache: false,
contentType: false,
processData: false,
success: function (data) {
var blob = new Blob([data]);
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = textName;
link.click();
}, error: function (data) { alert("error"); }});
I use web api for downloading the file
public HttpResponseMessage Download(string fileName)
{
string filePath = Path.Combine(PATH, fileName.Replace('/', '\\'));
byte[] pdf = System.IO.File.ReadAllBytes(filePath);
HttpResponseMessage result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new ByteArrayContent(pdf);
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "MyPdf.pdf";
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return result;
}
Please help me
Referencing Download pdf file using jquery ajax
jQuery has some issues loading binary data using AJAX requests, as it
does not yet implement some HTML5 XHR v2 capabilities
It provides two options for you try. I won't repeat them here as they belong to that answer. Check the link.
On the server side, I've had success downloading PDF files using this method.
[HttpPost]
public HttpResponseMessage Download(string fileName)
{
string filePath = Path.Combine(PATH, fileName.Replace('/', '\\'));
byte[] pdf = System.IO.File.ReadAllBytes(filePath);
//content length for header
var contentLength = pdf.Length;
var statuscode = HttpStatusCode.OK;
var result = Request.CreateResponse(statuscode);
result.Content = new StreamContent(new MemoryStream(buffer));
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
result.Content.Headers.ContentLength = contentLength;
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "MyPdf.pdf";
return result;
}
Not that much different to your original.
You should also check to make sure that the original file was not corrupt on the server if you are reading from disk/database or if you are dynamically generating the file.
The problem is probably your Content-Disposition header. You need inline, but you have attachment.
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline");
What you have now tells the browser to specifically send the file directly, and never attempt to display it in-browser. Chrome's internal PDF viewer currently chokes when you do this.
More: Content-Disposition:What are the differences between "inline" and "attachment"?

ASP .net Web Api downloading and viewing images

I want to download images from a server and display them in the browser. But when I enter the url in the browser (localhost:port/api/service/imageID), the download box appears asking me wether to save or open the image. But I want the image to be straight displayed in the browser.
This is my controller 'Get' method:
public HttpResponseMessage Get(int id)
{
HttpResponseMessage response;
var image = _repository.RetrieveImage(id);
if (image == null)
{
response = new HttpResponseMessage(HttpStatusCode.NotFound);
}
else
{
response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(new MemoryStream(image.ImageData));
response.Content = new ByteArrayContent(image.ImageData);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = image.OriginalFileName;
response.Content.Headers.ContentType = new MediaTypeHeaderValue(image.Mime);
response.Content.Headers.ContentLength = image.ImageData.Length;
}
return response;
Thanks a lot for any help
Don't use the "attachment" content disposition header. Using that header instructs browsers to download the specified file instead of showing it inline.
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
For completeness, note that removing the Content-Disposition will also remove any hint of the file's name when saved using "Save As" context menu, and a filename will be suggested based on the URL, which in this case will be something like "42.jpg", because the last part of the URL is an ID. If you want to preserve the file name during save, change the Content-Disposition to "inline":
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline")
{
FileName = image.OriginalFileName,
Size = image.ImageData.Length
};
For you scenario, i think you could just return a StreamContent and provide the appropriate content-type header of this content. (ex: image/jpeg)

Downloading a file with response doesn't show a filesize

I have this piece of code in a function:
Response.Clear();
Response.ContentType = "text/xml; charset=utf-8";
Response.AddHeader("Content-Disposition", "attachment; filename=test.xml");
// Put xml into response here
Response.End();
And this works, but, when it, it doesn't show a file size, in firefox it shows the filesize -1 and in chrome and ie it doesn't show a file size at all. How can I show the file size?
Did you try giving this:
Response.AddHeader("Content-Length", someBytes.Length.ToString());
If the content-length is set the web browser will show a progress bar while downloading. This is a very important usability feature for medium and large files, and you really want it. You want your user to know how far along they are, so they don't cancel the download and start it over, or worse just abandon your site.
Refer
If your Response is of type System.Net.Http.HttpResponseMessage, you can insert a Content-Length header by using:
response.Content.Headers.ContentLength = <length in bytes>;
If you are stream a file your code could look like:
FileStream fileStream = File.Open("<source file name>", FileMode.Open);
HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(fileStream);
response.Content.Headers.ContentLength = fileStream.Length;
response.Content.Headers.ContentType =
new MediaTypeHeaderValue("<media type e.g. application/zip>");
response.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("file")
{
FileName = "<destination file name>"
};
return response;

Categories