从Asp Net Web API控制器导出到Excel

我正在使用新的Web应用程序,即使用Web API作为业务层和淘汰Js作为客户端框架工作进行绑定。 我有一个要求,如将一定的search条件传递给Web API控制器,并从数据库获取数据,并创build和发送Excel / MS-Word文件作为一个可下载的内容。

我对Web API和Knock都是新手,我在网上search并获得部分解决scheme,我正在寻找这个用例的更优化的解决scheme。

以下是我的代码:

客户:

function GetExcelFile() { var $downloadForm = $("<form method='POST'>") .attr("action", baseUrl + "api/FileHandler/GetExcelFileTest") .attr("target", "_blank") $("body").append($downloadForm); $downloadForm.submit(); $downloadForm.remove(); } 

点击button点击此代码片段即可创build表单并从Web API获取响应。

Web API代码:

 [HttpPost] public HttpResponseMessage GetExcelFileTest() { var response = new HttpResponseMessage(); //Create the file in Web App Physical Folder string fileName = Guid.NewGuid().ToString() + ".xls"; string filePath = HttpContext.Current.Server.MapPath(String.Format("~/FileDownload/{0}", fileName)); StringBuilder fileContent = new StringBuilder(); //Get Data here DataTable dt = GetData(); if (dt != null) { string str = string.Empty; foreach (DataColumn dtcol in dt.Columns) { fileContent.Append(str + dtcol.ColumnName); str = "\t"; } fileContent.Append("\n"); foreach (DataRow dr in dt.Rows) { str = ""; for (int j = 0; j < dt.Columns.Count; j++) { fileContent.Append(str + Convert.ToString(dr[j])); str = "\t"; } fileContent.Append("\n"); } } // write the data into Excel file using (StreamWriter sw = new StreamWriter(fileName.ToString(), false)) { sw.Write(fileContent.ToString()); } IFileProvider FileProvider = new FileProvider(); //Get the File Stream FileStream fileStream = FileProvider.Open(filePath); //Set response response.Content = new StreamContent(fileStream); response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); response.Content.Headers.ContentDisposition.FileName = fileName; response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/ms-excel"); response.Content.Headers.ContentLength = fileStream.Length; //Delete the file //if(File.Exists(filePath)) //{ // File.Delete(filePath); //} return response; } 

使用此代码,我可以下载一个Excel文件。 尽pipe如此,我仍然有一些更加开放的问题来使代码最优化。

Q1)我需要将视图模型(search标准)传递给API控制器使用dynamic创build表单? (或)从Web API获取Excel文件的更好方法。

Q2)我相信这不是在物理文件夹中创buildExcel文件并获取FileStream并作为响应发送的好方法。 如何在飞行中做? 或者任何其他最佳方式。

请build议我做更好的方法..谢谢

Q1)您可以非常轻松地传递视图模型,但同样容易从发布的表单中获取信息。

传递视图模型

如果要将视图模型传递给WebAPI方法,请记住该方法必须将具有相同属性的对象作为参数。 因此,如果您希望回发的对象始终具有相同的属性,那么使用相同的属性构build一个服务器端类并接收该类的实例是微不足道的。

要回发这个客户端对象,你可以做这样的事情(使用jQuery,我看到你已经在使用):

 $.ajax({ contentType: "application/json", data: my-view-model.toJSON(), type: "POST", url: baseUrl + "api/FileHandler/GetExcelFileTest" }); 

我没有在这里附加任何successerror处理程序,因为JavaScript不关心返回,但是您可能希望添加一些处理程序,以防在您的WebAPI方法中引发exception。 我build议通过将以下内容添加到$.ajax()调用中来实现这一点:

 statusCode: { 500: function(jqXhr, textStatus, errorThrown) { }, [other HTTP error codes] } 

[阅读$.ajax()调用的文档。]

这里还有一个小技巧:当你调用my-view-model.toJSON() (或者self.toJSON() ,如果你的view-model中调用的话),Knockout将首先确定你的视图模型是否包含toJSON()方法。 如果是这样,它将使用这种方法; 如果不是那么它会调用浏览器的这个函数的实现。 但是,浏览器的这个函数的实现将把所有的东西都串联起来,如果你的视图模型中有很长的select列表,那么这个东西就特别的长。 因此,如果你只希望发回视图模型属性的一个子集,那么在你的视图模型上定义你自己的toJSON函数就像这样:

 var toJSON = function() { return { Property1: ..., Property2: ... }; } 

[了解更多关于将视图模型转换为JSON的信息 。]

按原样发布表单

如果您不希望花费精力进行视图模型布线,那么您可以将表格完全按照您的问题发布。 然后可以使用从表单中检索值

 Request.Form["my-field"]; 

Q2)

您可能正确地指出,在物理文件夹中创buildExcel文件并不明智。 但是,据我所知(如果别人说,感兴趣),你将不得不使用第三方库。 微软提供了一个Office自动化库,但是我怀疑你也需要将Office安装在同一个位置。

dynamic创buildExcel电子表格是我已经做了好几次,但实际上我使用Aspose.Cells,这需要一个许可证。 虽然我创build了一个物理版本然后删除它,但我相信Aspose.Cells可能允许您将它创build为一个stream。 但是看看周围,肯定还有其他提供Excel自动化的库。

从服务器返回文件

单独调用$.ajax({...})将不允许您向用户显示“另存为…”对话框。 我在这种情况下做了什么 – 如果你希望将生成的文件只存储在内存中(例如FileStream),而不是在文件系统上,这种方式将不起作用,而是响应$.ajax({...})使用生成文件的文件名进行调用。

下一步是将用户引导到该文件名。

所以我在我的JavaScript中有这样的东西:

 $.ajax({ dataType: "json", type: "GET", // you'll probably want POST in your case url: ..., success: function(response) { if (response && response.Uri && response.Uri.length) { window.location.href = [root URL] + response.Uri; } } }); 

但是别担心这个redirect。 window.location.href直接指向服务器上的一个文件夹,不需要任何控制器。 因为浏览器接收到一个文件,它会在同一个网页上显示“另存为…”对话框。