Reputation: 1357
Inside my controller I am using ServiceStack.Text to serialize a List and wish to return it to the client.
I am passing json that gets passed and manipulated into a list of objects that I then want to return as a csv. I can confirm this part is working. The client reports the request was successful but no file is available for download. if i console.log the response it prints the csv string.
I actually receive a list of json strings that I deserialize and append to a single list.Again, I can confirm this is working as expected.
Here is the Code:
[ValidateInput(false)]
[HttpPost]
public FileContentResult DownloadCSV(List<string> json, string delimiter, string method)
{
var respCSV ="";
if (method == "combine")
{
List<AgmtToCSV> comb = new List<AgmtToCSV>();
foreach (var i in json)
{
var d = Newtonsoft.Json.JsonConvert.DeserializeObject<List<AgmtToCSV>>(i);
foreach (var u in d)
{
comb.Add(u);
}
}
var csv = CsvSerializer.SerializeToCsv(comb);
respCSV = csv;
}
return File(new System.Text.UTF8Encoding().GetBytes(respCSV), "text/csv", "ExpirationReport.csv");
//return File(respCSV);
}
EDIT
Here is what the response look like:
Cache-Control:private
Content-Disposition:attachment; filename=ExpirationReport.csv
Content-Encoding:gzip
Content-Length:3117
Content-Type:text/csv
Date:Thu, 20 Jul 2017 17:42:16 GMT
Server:Microsoft-IIS/8.0
Vary:Accept-Encoding
X-AspNet-Version:4.0.30319
X-AspNetMvc-Version:5.2
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?SDpcZGV2ZWxvcG1lbnRcQWdyZWVtZW50LVZpZXdlclxBViAxLjEuMyBkZXZcQVZcQVZcSG9tZVxEb3dubG9hZENTVg==?=
Here is the jquery request and how it handles the successful response..
$.post('@Url.Action("DownloadCSV", "Home")', { "json":dta, "delimiter":del, "method":"combine"}, function (r) {
console.log("Success");
console.log(r);
});
UPDATE - Solution
Was able to get this to work with the accepted answer: The success function was the key here. It creates a link that points to the download and then initiates it.
$.post('@Url.Action("DownloadCSV", "Home")', { "json":dta, "delimiter":del, "method":"combine"}, function (r) {
console.log("Success");
var link = document.createElement("a");
link.id = "lnkDwnldLnk";
var converted = r;
document.body.appendChild(link);
var csv = converted;
blob = new Blob([csv], { type: 'text/csv' });
window.URL = window.URL || window.webkitURL;
var csvUrl = window.URL.createObjectURL(blob);
var filename = 'ExpirationReport.csv';
$("#lnkDwnldLnk")
.attr({
'download': filename,
'href': csvUrl
});
var ua = window.navigator.userAgent;
var msie = ua.indexOf("MSIE ");
if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) // If Internet Explorer, return version number
{
window.navigator.msSaveOrOpenBlob(blob, filename);
}
else {
$('#lnkDwnldLnk')[0].click();
}
document.body.removeChild(link);
});
Upvotes: 0
Views: 1674
Reputation: 481
I'm not exactly sure that my answer will do exactly as you want but still. I have this code that I'm using that basically takes in a JSON object, transforms it in a CSV and downloads it in the browser.
The controller code that goes to a service to get a list of objects and returns it as JSON.
public ActionResult DownLoadExcel(long BatchNumber)
{
Context context = new Context();
IQueryable<string> ICodeList = context.Codes.OrderByDescending(c => c.CreatedDateTime).Where(c => c.BatchNumber == BatchNumber).Select(c => c.Id); ;
var codeList = ICodeList.ToList();
return Json(codeList, JsonRequestBehavior.AllowGet);
}
The AJAX call that gets the JSON list from the controller and transforms it into a CSV. Then it creates and fake a anchor and simulates a click on it to trigger the download.:
<script type="text/javascript">
function getExcel(batchNumber)
{
$.ajax({
type: 'GET',
url: '@Url.Action("DownloadExcel", "BatchCode")',
data: { BatchNumber: batchNumber },
cache: false,
success: function (result) {
var converted = ConvertToCSV(result);
//this trick will generate a temp "a" tag
var link = document.createElement("a");
link.id = "lnkDwnldLnk";
//this part will append the anchor tag and remove it after automatic click
document.body.appendChild(link);
var csv = converted;
blob = new Blob([csv], { type: 'text/csv' });
window.URL = window.URL || window.webkitURL;
var csvUrl = window.URL.createObjectURL(blob);
var filename = 'file.csv';
$("#lnkDwnldLnk")
.attr({
'download': filename,
'href': csvUrl
});
var ua = window.navigator.userAgent;
var msie = ua.indexOf("MSIE ");
if (msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./)) // If Internet Explorer, return version number
{
window.navigator.msSaveOrOpenBlob(blob, filename);
}
else{
$('#lnkDwnldLnk')[0].click();
}
document.body.removeChild(link);
}
});
}
function ConvertToCSV(objArray) {
var array = typeof objArray != 'object' ? JSON.parse(objArray) : objArray;
var str = '';
for (var i = 0; i < array.length; i++) {
var line = array[i];
str += line + '\r\n';
}
return str;
}
</script>
And finally you need and empty a in your HTML
<a hidden="hidden"></a>
Upvotes: 1