In Angular I'm trying to download an excel file from my Web API Server
If I call my API from an <a> component just like this:
Download
The file downloads fine and without handling the response I get the desired behaviour:
How can I get the same result making the request from my Angular DownloadService and handling the result on .subscribe()?
this.downloadService.download()
.subscribe(file => {/*What to put here for file downloading as above*/});
Note that the server creates the response like this:
byte[] b = File.ReadAllBytes(HttpRuntime.AppDomainAppPath + "/files/" + "file.xlsx");
var dataStream = new MemoryStream(b);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(dataStream);
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = "File";
response.Content.Headers.ContentType = new MediaTypeHeaderValue(MimeMapping.GetMimeMapping("file.xlsx"));
return response;
Thanks in advance! :)
try this work around:
.subscribe(file =>
{
const a = document.createElement('a');
a.setAttribute('type', 'hidden');
a.href = URL.createObjectURL(file.data);
a.download = fileName + '.xlsx';
a.click();
a.remove();
});
The comment above should work, but here is another way
.subscribe(file) {
const blob = new Blob([file], { type: 'text/csv' }); // you can change the type
const url= window.URL.createObjectURL(blob);
window.open(url);
}
You can add js-file-download library which supports all browsers
npm install js-file-download --save
you can use window.URL.createObjectURL(blob); but IE does not support it...
here is my code for downloading Excel files from the Backend
import axios from 'axios';
import * as FileSaver from 'file-saver';
const result: any = await axios.create().post("http://localhost:8080/file",
{
responseType: "arraybuffer",
});
let blob = new Blob([result.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });
FileSaver.saveAs(blob, "export.xlsx");
Related
I've been having some problems when I try to convert a byte[] coming from C# into a pdf file using Angular.
When I perform the conversion the file is created but is corrupted and it can't be opened "We can't open this file", the file content is just basic text "Hello world".
Please let me know if you have any answer to this problem, the code I am using is below and I also try using "import { saveAs } from 'file-saver';" but it didn't work.
// THE WEB API CONTROLLER THAT GETS THE PDF BYTE ARRAY
[HttpPost("CreatePDF")]
public async Task<HttpResponseMessage> CreatePDF([FromBody] PDFContent pdfContent)
{
byte[] pdf = await _pdfGenerator.GeneratePDF(pdfContent.HtmlContent);
var result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent(pdf);
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
return result;
}
// UI SERVICE LAYER THAT CALLS THE SERVER SIDE
createPdfReport(pdfContent: PDFContent): Observable<any> {
return this.restApi.create("CreatePDF",pdfContent).pipe(
tap(pdf =>
console.log('pdf = ' + pdf)
));
}
// THE COMPONENT THAT CALLS THE SERVICE LAYER AND WAITS FOR THE RESPONSE
this.historyService.createPdfReport(pdfContent).subscribe(data => {
var file = new Blob(data, { type: 'application/octet-stream' })
var fileURL = URL.createObjectURL(data);
const link = document.createElement('a');
link.setAttribute('target', '_blank');
link.setAttribute('href', fileURL);
link.setAttribute('download', `file.pdf`);
document.body.appendChild(link);
link.click();
link.remove();
});
}
This is the response I get in Angular after the controller returns the byte[]:
Helo, i already search on Google and here (StackOverflow) but no any solution i complete.
I Have a Excel file in my folder and i need to create a method on my controller to download this file.
And in my React Web Site i need to get this file to user computer.
I try to use ActionResult, FileStreamResult, HttpResponseMessage and other, read file from folder with File.ReadAllbytes, put the Header on response.
On the final i get this.
{ FileContents: "allcontentoffilehere....", Contenttype: "application/octet-stream", FileDownloadName: "filename.xls"}
And using this JavaScript do download:
var bytes = new Uint8Array(responseDownloadFile.data.FileContents);
var blob = new Blob([bytes], {
type: responseDownloadFile.data.ContentType
});
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = responseDownloadFile.data.FileDownloadName;
document.body.appendChild(link);
link.click();
But the file when download is corrupted.
Any on can help me?
Try to return HttpResponseMessage type on your API
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new ByteArrayContent([file bytes]);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/file type");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "filename.xlsx"
};
return result;
And on your Front end execute code:
window.location.href = "link to your api endpoint to download excel";
I'm trying to deliver a zip archive in response to an AJAX POST request made from Axios to WebAPI.
On the client side I have
import AjaxDownload from "../../data/AjaxDownload";
AjaxDownload.post(id, pageRecords, {
responseType: "blob"
}).then((response) => {
let blob = new Blob([response.data], { type: extractContentType(response) }),
url = window.URL.createObjectURL(blob);
window.open(url, "_self");
}).catch((error) => {
// ...
}).then(() => {
// ...
});
function extractContentType(response: AxiosResponse): string {
return response.headers["content-type"] || "";
}
// AjaxDownload:
import * as axios from "axios";
import { apiUrl } from "./Ajax";
const ajax = axios.default.create({
baseURL: new URL("download", apiUrl).toString(),
timeout: 3600000 // 1 hour
});
export default ajax;
That posts to the following WebAPI method - and the POST part of that client-side logic works exactly as expected.
[HttpPost]
[Route("download/{id:guid}")]
public async Task<HttpResponseMessage> Download(Guid id, [FromBody] IEnumerable<PageRecord> pageRecords)
{
var stream = await _repo.GetAsArchiveStream(id,
pageRecords,
true).ConfigureAwait(false);
stream.Position = 0;
var result = new HttpResponseMessage(HttpStatusCode.OK) {Content = new StreamContent(stream)};
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {FileName = $"{...}.zip"};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); // "application/zip" has same result
result.Content.Headers.ContentLength = stream.Length;
return result;
}
However, the browser displays the result.Content as a JSON object, without the zip archive. I assume that the it's displaying as JSON because the request mentions JSON, but why does it appear to ignore the binary content - particularly as the Content-Type header details the type of content?
And as you can see, the JavaScript is also expecting to read in the content as a blob.
I don't see how my code differs meaningfully from this answer - please explain if there is a crucial difference.
On the server-side, I've also tried returning...
return new FileStreamResult(stream, "application/zip");
The problem with this approach is that there's no way to set a filename. Firefox does download the zip albeit with a random name while Chrome doesn't appear to download anything at all.
There must be a way to do this, right? To POST a request to a WebAPI method which returns a zip archive, and the client-side then presents a Save dialog? What am I missing?
I managed to solve this simply by returning the zip from the controller action using...
return File(stream,
"application/zip",
"FILENAME.zip");
And in the client-side code I can fetch the filename from the headers using some JavaScript found in this SO answer.
let blob = new Blob([response.data], { type: extractContentType(response) }),
downloadUrl = window.URL.createObjectURL(blob),
filename = "",
disposition = response.headers["content-disposition"];
if (disposition && disposition.indexOf("attachment") !== -1) {
let filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/,
matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) {
filename = matches[1].replace(/['"]/g, '');
}
}
var a = document.createElement("a");
// safari doesn't support this yet
if (typeof a.download === 'undefined') {
window.location.href = downloadUrl;
} else {
a.href = downloadUrl;
a.download = filename;
document.body.appendChild(a);
a.click();
}
I have several export routes on an asp.net core application, but all of them are accessed by a GET request, eg: /api/{projectid}/{parameter}
These requests are generating xlsx files and sending them to the client. Now I have a similar request but I have to pass a long array to the method, so I would like to make it into a POST method and send the array (and other parameters) in the http body.
I get the correct response from the server (an array buffer starting with PK...) but I can't tell angular to save it as a file as I did with the similar GET requests. If I rewrite this back to start a GET request it works fine. What am I doing wrong?
Controller method:
[HttpPost("[action]")]
public IActionResult Export([FromBody] DistributionExportPostModel model)
{
var project = _ctx.Projects.FirstOrDefault(x=>x.Id == model.ProjectId);
byte[] xlsx = createXlsxFile(project, model.Selection, model.ComparisonBase);
var mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
var fileName = $"TaskExport-"+project.Name+"-"+DateTime.Now.ToString("yyyyMMddHHmmss")+".xlsx";
return File(xlsx, mimeType, fileName);
}
Angular provider method:
export(projectid:string, selection:string[], comparisonBase:string):Promise<any[]> {
//let headers:Headers = new Headers();
//headers.append('Accept', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
//let params: URLSearchParams = new URLSearchParams();
let requestOptions = new RequestOptions();
requestOptions.responseType = ResponseContentType.ArrayBuffer;
return new Promise<any[]>((resolve) =>
this.http.post('/api/Distribution/Export', {
//'+projectid+'/'+comparisonBase+'/'+selection.join(','),
'ProjectId': projectid,
'Selection': selection,
'ComparisonBase': comparisonBase
}, requestOptions).subscribe((res) => {
window.open(res.url, '_blank');
resolve();
})
);
}
Below should work on Chrome.
var blob = new Blob(yourData, {type: "octet/stream"});
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = name;
a.click();
window.URL.revokeObjectURL(url);
For IE and Firefox, try this:
window.navigator.msSaveBlob(blob, filename);
You may need to add the anchor to the DOM before clicking it.
I have an ASP.NET SOAP web service, i have been using it for several calls from php and jquery AJAX but now i need to download files from the server. my php/jquery application is on wamp. The Web service and the application consuming it are hosted on different servers. APACHE AND IIS.
With this code, the file donloads but cannot open with pdf.
Thanks in advance. I have tried Jquery file download plugin too
This is my webservice code to download the file.
System.IO.FileStream fs1 = null;
fs1 = System.IO.File.Open(file_path, FileMode.Open, FileAccess.Read);
byte[] b1 = new byte[fs1.Length];
fs1.Read(b1, 0, (int)fs1.Length);
fs1.Close();
return b1;
This is my JQuery code
`
var oReq = new XMLHttpRequest();
oReq.open("GET",
"http://localhost:54761/EXT/ExternalSolicitorWebService.asmx/Download?
file_path="+$(dat).data("payload"), true);
oReq.responseType = "arraybuffer";
oReq.setRequestHeader('Content-type', 'application/json; charset=utf-8');
oReq.onload = function() {
var blob = new Blob([this.response], {type: $(dat).data("filetype").toLowerCase});
var downloadUrl = URL.createObjectURL(blob);
var a = document.createElement("a");
a.href = downloadUrl;
a.download = $(dat).data("filename");
document.body.appendChild(a);
a.click();
$(window).on('focus', function(e) {
$(a).remove();
});
};
oReq.send();