Reputation: 193
I have a controller action to create a DataTable using filtered data sent from the client via AJAX, which is working fine on its own:
[HttpPost]
public JsonResult RetrieveStaffData(FilterModel jsonData)
{
var data = (from i in db.StaffList
where i.Username.Contains(jsonData.Username)
&& i.Surname.Contains(jsonData.Surname)
&& i.Forename.Contains(jsonData.Forename)
// etc...
orderby i.Surname ascending)
.ToList();
if (data == null)
return Json(new { success = "False", message = "filter brought back no results" });
DataExport(ToDataTable(data));
return Json(new { success = "True", message = "data retreival successful" });
}
I also have an existing DataExport controller action which converts a DataTable to an excel document and sends it to the client for download, on its own this works fine as well:
public void DataExport(DataTable dt)
{
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment;filename=spreadsheetname.xlsx");
using (var p = new ExcelPackage())
{
var ws = p.Workbook.Worksheets.Add("StaffList");
ws.Cells.LoadFromDataTable(dt, true);
ws.Cells.AutoFitColumns();
var ms = new System.IO.MemoryStream();
p.SaveAs(ms);
ms.WriteTo(Response.OutputStream);
}
Response.OutputStream.Flush();
Response.OutputStream.Close();
Response.End();
}
The problem is that when the DataExport action is called before the return
the file is sent to the client as the AJAX response instead of a file download, which comes out as garbled binary in the response.
How can I send the client a response message and then send the file for download afterwards? Would Async/Await help here? I think I can use Blobs in JS to handle the file clientside but just wondering if there's a better way to do it.
Thanks in advance for any help that can be provided.
Upvotes: 0
Views: 641
Reputation: 61849
You have to get the client to make a secondary request, and not via ajax - you can't download a file via ajax. Use something like window.open, directed to the URL of the a Download action method, which runs the export method.
I don't know how you've coded your ajax request, but in the callback which indicates a successful response, do something along the lines of:
window.open(@Url.Action("DownloadData"));
It's also possible, looking at your code, that you don't need the ajax request at all - all it seems to return is a "yes/no" type response. Perhaps the page should simply open the window to the "Download" action directly, which would run the query and then the DataExport function.
Upvotes: 1