0

I am trying to download or at least open a generated csv file via ajax. I have managed to log the output and everything comes out fine. Is it possible to do it via ajax or must I try it another way? Controller

[HttpPost]
public FileResult GenerateEventLogsReport([FromBody]GenericReportDateViewModel Input)
{
    var report = eventLogsData.Report(Input.StartDate, Input.EndDate);
    var sb = new StringBuilder();
    foreach(var item in report)
    {
        sb.AppendLine(item.Id + "," + item.Identity + "," + item.Level + "," + item.Logger + "," + item.Message + "," + item.TimeStamp + "," + item.Action);
    }
    return File(new UTF8Encoding().GetBytes(sb.ToString()),"text/csv","EventLogs_"+ Input.StartDate +"_to_"+ Input.EndDate +".csv");
}

AJAX

var event_form_data = {
    "StartDate": $("#eventStartDate").val(),
    "EndDate": $("#eventEndDate").val(),
};
$.ajax({
    url: "@Url.Action("GenerateEventLogsReport", @ViewContext.RouteData.Values["controller"].ToString())",
    method: "POST",
    data: JSON.stringify(event_form_data),
    contentType: "application/json",
    success: function (result) {
        console.log(result);
        window.open("data:application/csv", result, "_blank");
    },
    error: function (error) {
        console.log(error);
    }
});
JianYA
  • 2,750
  • 8
  • 60
  • 136

1 Answers1

3

In short, you need to create an anchor, assign an object URL for the result to the href, and then call click() on it. Additionally, your $.ajax call will need to specify that you're expecting a blob response, as the default in jQuery is to treat the response as text. What that boils down to is code like the following:

$.ajax({
    url: "@Url.Action("GenerateEventLogsReport", @ViewContext.RouteData.Values["controller"].ToString())",
    method: "POST",
    xhrFields: {
        responseType: 'blob'
    },
    data: JSON.stringify(event_form_data),
    contentType: "application/json",
    success: function (result) {
        var a = document.createElement('a');
        var url = window.URL.createObjectURL(result);
        a.href = url;
        a.download = 'report.csv';
        document.body.append(a);
        a.click();
        a.remove();
        window.URL.revokeObjectURL(url);
    },
    error: function (error) {
        console.log(error);
    }
});

I also have a working CodePen to demo.

Chris Pratt
  • 232,153
  • 36
  • 385
  • 444
  • Thank you for your answer. I'm wondering if it would it be better if I just stored it in a temporary directory and then retrieved it from there and then deleted the file? – JianYA Jun 13 '19 at 13:44
  • No. For one, you'd need a way to clean it up afterwards, which means adding some sort of background job. Otherwise, you'd just litter this directory with reports. Further, you would then need to *serve* this directory. You can write the report to a temporary file, if you like, but that would only be for caching purposes. You should still keep this action to return the data directly, though. – Chris Pratt Jun 13 '19 at 13:47