Reputation: 109
I'm not sure what I want to do is even possible.
I'm currently working on an AngularJS web app and need implement a way to take data from my database, store it into a List<object>
, parse that List<object>
into a .csv file and load it in memory, that way I can send it back as HttpResponseMessage
.
I already have all the data in a List<object>
variable and will be using CSVHelper to parse that into a file, but all the examples I find online show me how to export the file locally with File.WriteAllText()
, and they all use File.OpenRead(filePath)
to read a file locally.
How can I create and store the file in memory and send it back as a HttpResponseMessage
?
EDIT:
After digging around I was able to come up with this, although it doesn't work. When I run the code I get "This site can't be reached. The Connection was rest. ERR_CONNECTION_RESET" from chrome.
Hope this helps with visualizing what I'm trying to do.
The Javascript
me.downloadFile = function (fileId) {
$http({
method: 'POST',
url: 'api/notices/CheckFileExists',
params: { fileId: fileId }
}).then(function success(result) {
if (result.data === 'Y') {
me.downloadOpen("POST", 'api/notices/DownloadFile?fileId=' + fileId, "", "");
}
else {
$mdToast.show(
$mdToast.simple()
.textContent(result.data)
.position("bottom right")
.hideDelay(2000)
);
}
});
};
me.downloadOpen = function (verb, url, data, target) {
var form = document.createElement("form");
form.action = url;
form.method = verb;
form.target = target || "_self";
if (data) {
for (var key in data) {
var input = document.createElement("input");
input.name = key;
input.value = typeof data[key] === "object" ? JSON.stringify(data[key]) : data[key];
form.appendChild(input);
}
}
form.style.display = 'none';
document.body.appendChild(form);
form.submit();
document.body.removeChild(form);
The C#
[HttpPost]
public HttpResponseMessage DownloadFile(int fileId)
{
var user = GetUser();
var fileContent = NoticesMethods.GetNoticeFile(fileId, user);
using (Globals.WebAppsImpersonator())
{
if (fileContent.Count > 0)
{
using (var mem = new MemoryStream())
using (var writer = new StreamWriter(mem))
using (var csvWriter = new CsvWriter(writer))
{
csvWriter.Configuration.Delimiter = ",";
csvWriter.WriteField("File ID");
csvWriter.WriteField("Account");
csvWriter.WriteField("Move Date");
foreach (var row in fileContent)
{
csvWriter.WriteField("\"" + row.FileId + "\"");
csvWriter.WriteField("\"" + row.Account + "\"");
csvWriter.WriteField("\"" + row.MoveDate + "\"");
}
writer.Flush();
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StreamContent(mem);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("text/csv");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "Notice.csv";
return result;
}
}
return new HttpResponseMessage(HttpStatusCode.NotFound);
}
}
Upvotes: 0
Views: 2115
Reputation: 109
I was able to find the answer by piecing together some stuff I found on the web. Incase anyone runs into a similar issue, this is the code that I have found to work for my case. The javascript is the same but I made some minor changes to the C#.
Instead of sending back StreamContent
I send back StringContent
. This way all I needed to do is write my data into a CSV file and then read it into a string.
Here is the code:
[HttpPost]
public HttpResponseMessage DownloadFile(int fileId)
{
var user = GetUser();
var fileContent = NoticesMethods.GetNoticeFile(fileId, user);
using (Globals.WebAppsImpersonator())
{
if (fileContent.Count > 0)
{
using (var mem = new MemoryStream())
using (var reader = new StreamReader(mem))
using (var writer = new StreamWriter(mem))
using (var csvWriter = new CsvWriter(writer))
{
csvWriter.Configuration.Delimiter = ",";
csvWriter.WriteField("File ID");
csvWriter.WriteField("Account");
csvWriter.WriteField("Move Date");
csvWriter.NextRecord();
foreach (var row in fileContent)
{
csvWriter.WriteField("\"" + row.FileId + "\"");
csvWriter.WriteField("\"" + row.Account + "\"");
csvWriter.WriteField("\"" + row.MoveDate + "\"");
csvWriter.NextRecord();
}
writer.Flush();
mem.Position = 0;
var file = reader.ReadToEnd();
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
result.Content = new StringContent(file);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("text/csv");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
result.Content.Headers.ContentDisposition.FileName = "Notice.csv";
return result;
}
}
return new HttpResponseMessage(HttpStatusCode.NotFound);
}
}
Upvotes: 0
Reputation: 107
To create a csv file and keep it in memory you'll need to instantiate a memory stream before your CSVHelper code. Then you can return the memory stream byte array as a base64 string from your controller.
[HttpGet]
public IHttpActionResult Get(params)
{
var result = "";
using (var memoryStream = new MemoryStream())
{
using (var streamWriter = new StreamWriter(memoryStream))
using (var csvWriter = new CsvWriter(streamWriter))
{
csvWriter.WriteRecords(listOfObjects);
}
result = Convert.ToBase64String(memoryStream.ToArray());
}
return Ok(result);
}
On the front end you'll probably want to take advantage of the FileSaver.js library. It requires you to convert the base64 string to a blob first. There are plenty of JS examples here (Creating a Blob from a base64 string in JavaScript).
Upvotes: 1