Here's what I'm using: AngularJS, BreezeJS on the client side. For the server, I'm using Web API and MVC 5.
I've been searching for ways on how to build and retrieve an excel spreadsheet from the server, but I'm at a loss.
I found this plugin called linqtocsv that helps greatly in building the csv file out of linq. The codeproject example is found here and the nuget link is found here.
I also found nice useage on a question on stackover flow: Web API HttpResponseMessage content return is incomplete
So after implementing the above plugin - linq to csv, and following the mentioned stackover question, nothing seems to be working.
Here is my server side code (both taken directly from the link mentioned already):
[HttpPost]
public HttpResponseMessage DistributorReport(JObject formValues)
{
try
{
var cqmo = formValues.ToObject<DistributorCQMO>();
var query = new FindDistributorsByLocationQuery
{
States = cqmo.States.Select(x => x.id),
Cities = cqmo.Cities.Select(x => x.id),
CitiesExclusion = cqmo.ExcludedCities.Select(x => x.id),
ZipCodes = cqmo.ZipCodes.Select(x => x.id),
ZipCodesExclusion = cqmo.ExcludedZipCodes.Select(x => x.id),
ProductFamily = cqmo.ProductFamily.id,
ProductSubFamilies = cqmo.ProductSubFamily.Select(x => x.id),
MatchAllFilter = cqmo.MatchAllFilter,
ClientTypeFilter = cqmo.ClientTypeFilter
};
IEnumerable<DistributorDTO> distributors = this.queryProcessor.Process(query).AsQueryable();
CsvFileDescription outputFileDescription = new CsvFileDescription
{
SeparatorChar = '\t', // tab delimited
FirstLineHasColumnNames = true
};
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new CsvContent<DistributorDTO>(outputFileDescription,
"ObserverTripList.csv",
distributors)
};
return response;
}
catch (Exception ex)
{
// logger.ErrorException("Exception exporting as excel file: ", ex);
return Request.CreateResponse(HttpStatusCode.InternalServerError);
}
}
and here's the helper class:
public class CsvContent<T> : HttpContent
{
private readonly MemoryStream _stream = new MemoryStream();
public CsvContent(CsvFileDescription outputFileDescription, string filename, IEnumerable<T> data)
{
var cc = new CsvContext();
var writer = new StreamWriter(_stream);
cc.Write(data, writer, outputFileDescription);
writer.Flush();
_stream.Position = 0;
Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
Headers.ContentDisposition.FileName = filename;
}
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return _stream.CopyToAsync(stream);
}
protected override bool TryComputeLength(out long length)
{
length = _stream.Length;
return true;
}
}
I tried using breeze to make my post, which returns the data wrapped up in the breeze object, and if after digging into the returned object, into it's httpreponse property, you'll see in its raw form, the tabbed delimited data, however, the content application is in application/json; charset=utf-8 and not of excel formatting.
EDIT:
I have the following now working:
$.ajax({
type: 'POST',
url: 'MappingTool.API/api/Report/DistributorReport',
data: JSON.stringify(jsonData),
contentType: 'application/json; charset=utf-8',
dataType: 'json',
success: function (returnValue) {
alert("success")
// window.location = '/Reports/Download?file=' + returnValue;
}
});
I'm getting the correct response and able to view all the results in fiddler and in chrome debugger. But how do I get the browser to download the file automatically?
any feedback is appreciated!
Edit:
Is this something that I should be fetching from an MVC controller or an API controller? It seems there is more support for an MVC controller, like the FileResult type that can be used in MVC; which would give me my automatic download: "exporting excel file to view mvc" I've seen it being done using an API controller; but isn't the point of an API controller to delegate simple data types, and not media content?