How to create and download file with Ajax in ASP.NET MVC

Introduction

When you use the Ajax call in ASP.NET MVC, you just can return a JSON object but not a file, if you want to do that, you need to create and save the file in server and return it’s path to Ajax, after that, you can call a redirect link for download the file, because this is a temp file, so you should need to delete it after download.

Using the code

The below demo code just for create and download an Excel file:

1. Create an Action for generate the Excel

[HttpPost]
public JsonResult ExportExcel()
{
    DataTable dt = DataService.GetData();
    var fileName = "Excel_" + DateTime.Now.ToString("yyyyMMddHHmm") + ".xls";
    
    //save the file to server temp folder
    string fullPath = Path.Combine(Server.MapPath("~/temp"), fileName);

    using (var exportData = new MemoryStream())
    {
        //I don't show the detail how to create the Excel, this is not the point of this article,
        //I just use the NPOI for Excel handler
        Utility.WriteDataTableToExcel(dt, ".xls", exportData);

        FileStream file = new FileStream(fullPath, FileMode.Create, FileAccess.Write);
        exportData.WriteTo(file);
        file.Close();
    }

    var errorMessage = "you can return the errors in here!";

    //return the Excel file name
    return Json(new { fileName = fileName, errorMessage = "" });
}

2. Create the download Action

[HttpGet]
[DeleteFileAttribute] //Action Filter, it will auto delete the file after download, I will explain it later
public ActionResult Download(string file)
{
    //get the temp folder and file path in server
    string fullPath = Path.Combine(Server.MapPath("~/temp"), file);

    //return the file for download, this is an Excel so I set the file content type to "application/vnd.ms-excel"
    return File(fullPath, "application/vnd.ms-excel", file);
}

3. We need to auto delete the file after download, so need to create an Action Filter

public class DeleteFileAttribute : ActionFilterAttribute
{
    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        filterContext.HttpContext.Response.Flush();

        //convert the current filter context to file and get the file path
        string filePath = (filterContext.Result as FilePathResult).FileName;
        
        //delete the file after download
        System.IO.File.Delete(filePath);
    }
}

4. Use the Ajax call in frontend

//I use blockUI for loading...
$.blockUI({ message: '<h3>Please wait a moment...</h3>' });    
$.ajax({
    type: "POST",
    url: '@Url.Action("ExportExcel","YourController")', //call your conntroller and action
    contentType: "application/json; charset=utf-8",
    dataType: "json",
}).done(function (data) {
    //console.log(data.result);
    $.unblockUI();

    //get the file name for download
    if (data.fileName != "") {
        //use window.location.href for redirect to download action for download the file
        window.location.href = "@Url.RouteUrl(new { Controller = "YourController", Action = "Download"})/?file=" + data.fileName;
    }
});

 

Leave a Reply

Your email address will not be published. Required fields are marked *