ajax - 从 Asp Net Web API Controller 导出到 Excel

标签 ajax excel knockout.js asp.net-web-api steam-web-api

我正在开发新的 Web 应用程序,它使用 Web API 作为业务层,并 knockout Js 作为客户端框架来绑定(bind)。我有一个要求,比如将某些搜索条件传递给 Web API Controller 并从数据库中获取数据,并即时创建和发送 Excel/MS-Word 文件作为可下载内容。

我是 Web API 和 Knock out 的新手,我正在网上搜索并获得部分解决方案,我正在寻找针对此用例的更优化解决方案。

下面是我的代码:

客户:

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

单击具有此代码片段的按钮可即时创建表单并从 Web API 获取响应。

网络 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 文件。我还有一些悬而未决的问题来优化此代码。

Q1) 我需要使用动态创建表单将 View 模型(搜索条件)传递给 API Controller ? (或)从 Web API 获取 Excel 文件的任何更好的方法。

Q2) 我确信这不是在物理文件夹中创建 Excel 文件并获取 FileStream 并作为响应发送的好方法。飞车怎么办?或任何其他最佳方式。

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

最佳答案

Q1) 您可以很容易地传递 View 模型,但从发布的表单中提取该信息也同样容易。

传递 View 模型

如果您想将 View 模型传递给 WebAPI 方法,请记住,所述方法必须将具有相同属性的对象作为参数。因此,如果您希望回发的对象始终具有相同的属性,那么构建具有相同属性的服务器端类并接收该类的实例就很简单了。

要回发此客户端对象,您可以执行以下操作(使用 jQuery,我看到您已经在使用它):

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

我没有在此处附加任何successerror 处理程序,因为 JavaScript 与返回无关,但您可能希望添加一些处理程序以防万一在您的 WebAPI 方法中抛出异常。我建议将以下内容添加到上面的 $.ajax() 调用中:

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

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

此处还有一个提示:当您调用 my-view-model.toJSON()(或 self.toJSON(),如果是从您的 View 模型中调用的) ) Knockout 将首先确定您的 View 模型是否包含 toJSON() 方法。如果是,它将使用此方法;如果不是那么它将调用浏览器的这个函数的实现。但是,浏览器对该函数的实现将序列化所有内容,如果您的 View 模型中有很长的选择列表,这可能会特别长。因此,如果您只想发回 View 模型属性的一个子集,那么在您的 View 模型上定义您自己的 toJSON 函数,如下所示:

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

[阅读更多关于将 View 模型转换为 JSON here .]

按原样发布表单

如果您不想花费精力进行 View 模型连接,那么您可以完全按照问题中的方式发布表单。然后,您可以使用

从表单中检索值
Request.Form["my-field"];

Q2)

您可能正确地指出在物理文件夹中创建 Excel 文件并不明智。但是,据我所知(如果有人不这么说的话,我会很感兴趣)你必须为此使用第 3 方库。 Microsoft 确实提供了一个 Office 自动化库,但我怀疑您还需要在同一位置安装 Office。

动态创建 Excel 电子表格是我做过几次的事情,但对于实际创建,我使用 Aspose.Cells,这需要许可证。虽然我确实创建了一个物理版本然后将其删除,但我相信 Aspose.Cells 可能允许您将其创建为流。但是环顾四周,肯定还有其他提供 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;
        }
    }
});

但是不要被这个重定向吓到。 window.location.href 直接指向服务器上的文件夹,不需要 Controller 。因为浏览器随后会收到一个文件,所以它会在保留在同一网页上的同时显示“另存为...”对话框。

关于ajax - 从 Asp Net Web API Controller 导出到 Excel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30695274/

相关文章:

vba - 在excel vba中的两个日期之间过滤

javascript - Knockoutjs - 具有绑定(bind)和状态

javascript - 在 Express 中接收邮政数据(不是表格)

MySQL 加载数据文件 (CSV) : replace/remove vertical tabs

java - Spring REST API,将原始类型传递给 Controller

php - 使用 fputcsv 连接列

javascript - 如何将扩展器添加到 Knockout 中的现有可观察对象

javascript - knockout js 可见数据绑定(bind)属性不显示结果

javascript - 在javascript中触发自动回发

ajax - JSF ajax 命令按钮不更新 primefaces 选择列表