Reputation: 2053
In MVC, we have used the following code to download a file. In ASP.NET core, how to achieve this?
HttpResponse response = HttpContext.Current.Response;
System.Net.WebClient net = new System.Net.WebClient();
string link = path;
response.ClearHeaders();
response.Clear();
response.Expires = 0;
response.Buffer = true;
response.AddHeader("Content-Disposition", "Attachment;FileName=a");
response.ContentType = "APPLICATION/octet-stream";
response.BinaryWrite(net.DownloadData(link));
response.End();
Upvotes: 91
Views: 198561
Reputation: 127
This worked for me :
httpContext.Response.Headers.Append("content-disposition", "attachment;filename=" + mytextfilename);
httpContext.Response.ContentType = "application/text";
httpContext.Response.WriteAsync(mytextfile);
Upvotes: 0
Reputation: 3647
You can try below code to download the file. It should return the FileResult
public ActionResult DownloadDocument()
{
string filePath = "your file path";
string fileName = "your file name";
byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
return File(fileBytes, "application/force-download", fileName);
}
Upvotes: 39
Reputation: 3008
A relatively easy way to achieve this is to use the built-in PhysicalFile
result, which is available to all controllers: MS Docs: PhysicalFile
A simple example:
public IActionResult DownloadFile(string filePath)
{
return PhysicalFile(filePath, MimeTypes.GetMimeType(filePath), Path.GetFileName(filePath));
}
Now of course you should never expose this kind of API, due to security concerns.
I typically shield the actual file paths behind a friendly identifier, which I then use to lookup the real file path (or return a 404 if an invalid ID was passed in), i.e.:
[HttpGet("download-file/{fileId}")]
public IActionResult DownloadFile(int fileId)
{
var filePath = GetFilePathFromId(fileId);
if (filePath == null) return NotFound();
return PhysicalFile(filePath, MimeTypes.GetMimeType(filePath), Path.GetFileName(filePath));
}
For those that are curious, the MimeTypes
helper is a great little Nuget package from the folks at MimeKit
Upvotes: 31
Reputation: 6746
Here is my Medium article, describing everything step by step (it also includes a GitHub repo): https://medium.com/@tsafadi/download-a-file-with-asp-net-core-e23e8b198f74
Any ways this is how the controller should look like:
[HttpGet]
public IActionResult DownloadFile()
{
// Since this is just and example, I am using a local file located inside wwwroot
// Afterwards file is converted into a stream
var path = Path.Combine(_hostingEnvironment.WebRootPath, "Sample.xlsx");
var fs = new FileStream(path, FileMode.Open);
// Return the file. A byte array can also be used instead of a stream
return File(fs, "application/octet-stream", "Sample.xlsx");
}
Inside the view:
$("button").click(function () {
var xhr = new XMLHttpRequest();
xhr.open("GET", "Download/DownloadFile", true);
xhr.responseType = "blob";
xhr.onload = function (e) {
if (this.status == 200) {
var blob = this.response;
/* Get filename from Content-Disposition header */
var filename = "";
var disposition = xhr.getResponseHeader('Content-Disposition');
if (disposition && disposition.indexOf('attachment') !== -1) {
var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
var matches = filenameRegex.exec(disposition);
if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, '');
}
// This does the trick
var a = document.createElement('a');
a.href = window.URL.createObjectURL(blob);
a.download = filename;
a.dispatchEvent(new MouseEvent('click'));
}
}
xhr.send();
});
Upvotes: 13
Reputation: 599
[HttpGet]
public async Task<FileStreamResult> Download(string url, string name, string contentType)
{
var stream = await new HttpClient().GetStreamAsync(url);
return new FileStreamResult(stream, contentType)
{
FileDownloadName = name,
};
}
Upvotes: 2
Reputation: 3587
my way is quite short and I think it suits most people's need.
[HttpPost]
public ActionResult Download(string filePath, string fileName)
{
var fileBytes = System.IO.File.ReadAllBytes(filePath);
new FileExtensionContentTypeProvider().TryGetContentType(Path.GetFileName(filePath), out var contentType);
return File(fileBytes, contentType ?? "application/octet-stream", fileName);
}
Upvotes: 0
Reputation: 101
Action method needs to return FileResult with either a stream, byte[], or virtual path of the file. You will also need to know the content-type of the file being downloaded. Here is a sample (quick/dirty) utility method. Sample video link How to download files using asp.net core
[Route("api/[controller]")]
public class DownloadController : Controller
{
[HttpGet]
public async Task<IActionResult> Download()
{
var path = @"C:\Vetrivel\winforms.png";
var memory = new MemoryStream();
using (var stream = new FileStream(path, FileMode.Open))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
var ext = Path.GetExtension(path).ToLowerInvariant();
return File(memory, GetMimeTypes()[ext], Path.GetFileName(path));
}
private Dictionary<string, string> GetMimeTypes()
{
return new Dictionary<string, string>
{
{".txt", "text/plain"},
{".pdf", "application/pdf"},
{".doc", "application/vnd.ms-word"},
{".docx", "application/vnd.ms-word"},
{".png", "image/png"},
{".jpg", "image/jpeg"},
...
};
}
}
Upvotes: 5
Reputation: 2141
Create a Service say FileService.
public class FileService
{
private readonly IHostingEnvironment _hostingEnvironment;
constructor(IHostingEnvironment hostingEnvironment)
{
this._hostingEnvironment = hostingEnvironment;
}
}
Add a method to FileService MimeType of the file
private string GetMimeType(string fileName)
{
// Make Sure Microsoft.AspNetCore.StaticFiles Nuget Package is installed
var provider = new FileExtensionContentTypeProvider();
string contentType;
if (!provider.TryGetContentType(fileName, out contentType))
{
contentType = "application/octet-stream";
}
return contentType;
}
Now add a method to download File,
public FileContentResult GetFile(string filename)
{
var filepath = Path.Combine($"{this._environment.WebRootPath}\\path-to-required-folder\\{filename}");
var mimeType = this.GetMimeType(filename);
byte[] fileBytes;
if (File.Exists(filepath))
{
fileBytes = File.ReadAllBytes(filepath);
}
else
{
// Code to handle if file is not present
}
return new FileContentResult(fileBytes, mimeType)
{
FileDownloadName = filename
};
}
Now add controller method and call GetFile method in FileService,
public IActionResult DownloadFile(string filename)
{
// call GetFile Method in service and return
}
Upvotes: 8
Reputation: 1165
Example for Asp.net Core 2.1+ (Best practice)
Startup.cs:
private readonly IHostingEnvironment _env;
public Startup(IConfiguration configuration, IHostingEnvironment env)
{
Configuration = configuration;
_env = env;
}
services.AddSingleton(_env.ContentRootFileProvider); //Inject IFileProvider
SomeService.cs:
private readonly IFileProvider _fileProvider;
public SomeService(IFileProvider fileProvider)
{
_fileProvider = fileProvider;
}
public FileStreamResult GetFileAsStream()
{
var stream = _fileProvider
.GetFileInfo("RELATIVE PATH TO FILE FROM APP ROOT")
.CreateReadStream();
return new FileStreamResult(stream, "CONTENT-TYPE")
}
Controller will return IActionResult
[HttpGet]
public IActionResult Get()
{
return _someService.GetFileAsStream() ?? (IActionResult)NotFound();
}
Upvotes: 7
Reputation: 14472
Your controller should return an IActionResult
, and use the File
method, such as this:
[HttpGet("download")]
public IActionResult GetBlobDownload([FromQuery] string link)
{
var net = new System.Net.WebClient();
var data = net.DownloadData(link);
var content = new System.IO.MemoryStream(data);
var contentType = "APPLICATION/octet-stream";
var fileName = "something.bin";
return File(content, contentType, fileName);
}
Upvotes: 87