Let’s explore real-world examples using the fetch + blob
pattern, targeting different file types and scenarios.
✅ 1. Download Static PDF via Fetch + Blob
🔹 JavaScript
<button onclick="downloadStaticPdf()">Download PDF</button>
<script>
function downloadStaticPdf() {
fetch('/files/sample.pdf') // Static file from wwwroot/files/
.then(res => res.blob())
.then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'sample.pdf';
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
})
.catch(err => console.error('Download failed', err));
}
</script>
✅ Good for static files in
wwwroot
.
✅ 2. Download File from Controller Action (e.g. Generated on the Fly)
🔹 C# Controller (.cs
file)
[HttpGet]
public IActionResult DownloadDynamicPdf()
{
// Simulate dynamic PDF generation
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/files/sample.pdf");
var fileBytes = System.IO.File.ReadAllBytes(filePath);
return File(fileBytes, "application/pdf", "generated-sample.pdf");
}
🔹 JavaScript
<button onclick="downloadDynamicPdf()">Download PDF</button>
<script>
function downloadDynamicPdf() {
fetch('/Home/DownloadDynamicPdf')
.then(res => res.blob())
.then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'generated-sample.pdf';
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
});
}
</script>
✅ Best for on-demand file generation or secure server-side files.
✅ 3. Download Excel File from Server (e.g., Report)
🔹 Controller
[HttpGet]
public IActionResult DownloadExcel()
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/files/report.xlsx");
var fileBytes = System.IO.File.ReadAllBytes(path);
return File(fileBytes,
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"report.xlsx");
}
🔹 JavaScript
<button onclick="downloadExcel()">Download Excel</button>
<script>
function downloadExcel() {
fetch('/Home/DownloadExcel')
.then(res => res.blob())
.then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'report.xlsx';
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
});
}
</script>
✅ Works for any binary file — Excel, Word, ZIP, images, etc.
✅ 4. Download File After Form Submission (POST)
Useful when you're sending data (e.g., form, filters) to generate the file first.
🔹 Controller
[HttpPost]
public IActionResult GeneratePdf([FromBody] ReportRequest request)
{
// Simulate PDF generation
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/files/sample.pdf");
var fileBytes = System.IO.File.ReadAllBytes(filePath);
return File(fileBytes, "application/pdf", "filtered-report.pdf");
}
public class ReportRequest
{
public string Filter { get; set; }
}
🔹 JavaScript
<button onclick="downloadFilteredPdf()">Download Filtered PDF</button>
<script>
function downloadFilteredPdf() {
fetch('/Home/GeneratePdf', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ filter: "LastMonth" })
})
.then(res => res.blob())
.then(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'filtered-report.pdf';
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
});
}
</script>
✅ Ideal for dynamic downloads based on user input.
✅ 5. Handle Filename from Response Header
If your controller sets the filename dynamically:
🔹 Controller
[HttpGet]
public IActionResult DownloadWithFilename()
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot/files/sample.pdf");
var bytes = System.IO.File.ReadAllBytes(path);
Response.Headers.Add("Content-Disposition", "attachment; filename=\"custom-name.pdf\"");
return File(bytes, "application/pdf");
}
🔹 JavaScript with filename parsing (advanced)
function downloadWithHeaderName() {
fetch('/Home/DownloadWithFilename')
.then(response => {
const contentDisposition = response.headers.get('Content-Disposition');
let fileName = "download.pdf";
if (contentDisposition) {
const match = contentDisposition.match(/filename="(.+)"/);
if (match.length > 1) fileName = match[1];
}
return response.blob().then(blob => ({ blob, fileName }));
})
.then(({ blob, fileName }) => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = fileName;
a.click();
URL.revokeObjectURL(url);
});
}
✅ Professional way if filename changes on server side.
🛡️ Tips for Production
-
Add error handling:
.catch()
in JS and try/catch in controller. -
Ensure content types are correct (e.g.,
"application/pdf"
,"application/zip"
, etc.). -
Use
[Authorize]
on secure download actions. -
Don't allow downloading files directly from sensitive paths.
No comments:
Post a Comment