javascript 从 mvc web api httpresponse 生成 csv 并通过 angularjs 接收以供下载
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20303988/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
generate csv from mvc web api httpresponse and receive it by angularjs for download
提问by raberana
I am trying to generate a CSV file from my web api and receive that file through angularjs. I have an API controller like below:
我正在尝试从我的 web api 生成一个 CSV 文件并通过 angularjs 接收该文件。我有一个如下所示的 API 控制器:
[HttpPost]
public HttpResponseMessage GenerateCSV(FieldParameters fieldParams)
{
var output = new byte[] { };
if (fieldParams!= null)
{
using (var stream = new MemoryStream())
{
this.Serialize(fieldParams, stream);
stream.Flush();
output = stream.ToArray();
}
}
var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(output) };
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "Fields.csv"
};
return result;
}
In my angularjs, i have this:
在我的 angularjs 中,我有这个:
$scope.save = function () {
var csvInput= extractDetails();
// File is an angular resource. We call its save method here which
// accesses the api above which should return the content of csv
File.save(csvInput, function (content) {
console.log(content);
// only creates a csv file with "[object Object]" written in it
var hiddenElement = document.createElement('a');
hiddenElement.href = 'data:text/csv;charset=utf-8,\uFEFF' + encodeURI(content.Parameters);
hiddenElement.target = '_blank';
hiddenElement.download = 'myFile.csv';
hiddenElement.click();
});
};
Lets say for example, in my API controller, the content of response is
比如说,在我的 API 控制器中,响应的内容是
output
{byte[152]}
[0]: 83
[1]: 101
[2]: 44
[3]: 67
[4]: 10
输出
{字节[152]}
[0]:83
[1]:101
[2]:44
[3]:67
[4]:10
When I receive this in angularjsand I put the value of content
in the console log (chrome), this is what I get:
当我在angularjs 中收到这个并将 的值放入content
控制台日志(chrome)时,这就是我得到的:
{Parameters: Array[1], $promise: Object, $resolved: true, $get: function, $save: function…}
0:"S"
1: "e"
2: ","
3: "C"
4: "?"
$promise: object
$resolved: true`
{参数:数组[1],$promise:对象,$resolved:true,$get:函数,$save:函数...}
0:"S"
1:“e”
2:“,”
3:“C”
4:“?”
$promise: 对象
$已解决:真`
Why did the
content
received in the angularjs contain characters already instead of a byte of array?How can I control the
content
in such a way that I will only use the csv related data and remove$promise
and$resolved
? Why are they included in the first place? How to remove them?What is the proper way of generating a csv if what I am doing is wrong? :|
为什么
content
在 angularjs 中接收到的已经包含字符而不是一个字节的数组?我怎样才能控制
content
这种方式,我只会使用 csv 相关数据并删除$promise
和$resolved
?为什么他们首先被包括在内?如何删除它们?如果我在做什么是错误的,那么生成 csv 的正确方法是什么?:|
回答by raberana
Forgot to update this, but i now found a way to solve this:
忘了更新这个,但我现在找到了解决这个问题的方法:
There will be two API's, one (POST) will remember the data to be used in the processing and another one (GET) which will dispense the file.
将有两个 API,一个 (POST) 将记住要在处理中使用的数据,另一个 (GET) 将分配文件。
POST:
邮政:
[HttpPost]
public async Task<HttpResponseMessage> BuildFile(FileParameters fileParams)
{
var guid = Guid.NewGuid().ToString();
if (fileParams!= null)
{
await Task.Run(() => FileContents.Add(guid, fileParams));
return this.Request.CreateResponse(HttpStatusCode.OK, new { Value = guid });
}
return this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid data");
}
In AngularJs, remember the guid returned and pass this to another api:
在 AngularJs 中,记住返回的 guid 并将其传递给另一个 api:
location.href = '/api/file/generatefile' + '?guid=' + generatedGuidFromAPI + '&reportName=' + $scope.reportName;
And here is the generatefile
API controller in MVC:
这是generatefile
MVC 中的API 控制器:
GET:
得到:
[HttpGet]
public async Task<HttpResponseMessage> GenerateFile(string guid, string reportName)
{
byte[] output = null;
if (FileContents.ContainsKey(guid))
{
await Task.Run(() =>
{
using (var stream = new MemoryStream())
{
this.CreateFile(FileContents[guid], stream);
stream.Flush();
output = stream.ToArray();
}
});
}
FileContents.Remove(guid);
if (output != null)
{
var result = new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(output) };
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = reportName + ".csv"
};
return result;
}
return this.Request.CreateErrorResponse(HttpStatusCode.NoContent, "No record found");
}
using location.href
will cause the browser to automatically download the file, asking you whether to save it or not.
使用location.href
会导致浏览器自动下载文件,询问您是否保存。
回答by itaylorweb
Here's how I do it: (tested in chrome)
这是我的方法:(在 chrome 中测试)
// WebAPI controller action
public IHttpActionResult Get(string rpt, DateTime date)
{
List<DailyMIReportViewModel> list = new List<DailyMIReportViewModel>();
// Do some stuff to generate list of items
// Download Requested
if (rpt == "dailymidl")
{
// Create byte array of csv
byte[] csvData = WriteCsvWithHeaderToMemory(list);
// create FileContentResult of cdv byte array
FileContentResult result = new FileContentResult(csvData, "application/octet-stream");
// set filename in FileContentResult
result.FileDownloadName = "Report.csv";
return Ok(result);
}
// Data Requested
return Ok(list);
// Client-side angularjs
// Called on button click
$scope.generateMIDownload = function (forDate) {
// Using $resource to return promise with FileContentResult payload
reportsRepository.dailymidl(forDate).$promise.then(
function (data) {
//ok
// NOTE: the base64 part is what got it working
var dataUrl = 'data:application/octet-stream;base64,' + data.FileContents
var link = document.createElement('a');
angular.element(link)
.attr('href', dataUrl)
.attr('download', data.FileDownloadName)
.attr('target','_blank')
link.click();
},
function (response) {
//not ok
});
}
// Reports Repository (for ref)
angular.module('msgnr').factory('reportsRepository', function ($resource) {
return {
dailymidl: function (date) {
return $resource('/api/Report/', { rpt: 'dailymidl', date: date, toDate: date }).get();
}
}
});
Incase it helps anyone else.
如果它可以帮助其他任何人。