通过ajax方法调用函数时未下载Excel文件

Nia*_*na 6 javascript asp.net-mvc excel jquery asp.net-mvc-4

情况

我正在开发一个应用程序,我可以在其中创建一个包含 X 个项目的网格,并且每个项目都有一个打印按钮。单击此打印按钮可以调用 ajax 函数,该函数将网格项的 ID 传递给控制器​​。我根据该 ID 检索相关数据,然后将其下载到 excel 文件中。(具体项目的检索尚未完成)

到目前为止我所拥有的

到目前为止,我已经有了下载 excel 文件的基本代码,以及我的 grid 。

问题

我面临的问题是,如果我单击“打印”按钮……什么也没有发生,即使我的exporttoexcel 函数中有一个断点,也会向我显示该函数已输入,我可以单步执行,尽管没有错误,但什么也没发生。但是,我添加了调用相同函数的随机按钮,当我单击该按钮时,下载了 excel 文件。因此,我认为这个问题与 aJax 有关。

代码

<input type="button" value="Test" onclick="location.href='@Url.Action("ExportToExcel", "Profile")'" />
Run Code Online (Sandbox Code Playgroud)

这是下载文件的代码。这是我添加的一个简单按钮。

function ExportToExcel(id) {
    $.ajax({
        type: "POST",
        url: "@Url.Action("ExportToExcel", "Profile")",
        data: { "id": id },
        dataType: "json"

    });
}
Run Code Online (Sandbox Code Playgroud)

这是我想要工作的功能,但它不起作用,我看不出我有什么问题。

导出到 Excel 代码

public void ExportToExcelx()
{
    var products = new System.Data.DataTable("teste");
    products.Columns.Add("col1", typeof(int));
    products.Columns.Add("col2", typeof(string));

    products.Rows.Add(1, "product 1");
    products.Rows.Add(2, "product 2");
    products.Rows.Add(3, "product 3");
    products.Rows.Add(4, "product 4");
    products.Rows.Add(5, "product 5");
    products.Rows.Add(6, "product 6");
    products.Rows.Add(7, "product 7");


    var grid = new GridView();
    grid.DataSource = products;
    grid.DataBind();

    Response.ClearContent();
    Response.Buffer = true;
    Response.AddHeader("content-disposition", "attachment; filename=MyExcelFile.xls");
    Response.ContentType = "application/ms-excel";

    Response.Charset = "";
    StringWriter sw = new StringWriter();
    HtmlTextWriter htw = new HtmlTextWriter(sw);

    grid.RenderControl(htw);

    //Response.Output.Write(sw.ToString());
    //Response.Flush();
    //Response.End();
    // =============


    //Open a memory stream that you can use to write back to the response
    byte[] byteArray = Encoding.ASCII.GetBytes(sw.ToString());
    MemoryStream s = new MemoryStream(byteArray);
    StreamReader sr = new StreamReader(s, Encoding.ASCII);

    //Write the stream back to the response
    Response.Write(sr.ReadToEnd());
    Response.End();



    //  return View("MyView");
}
Run Code Online (Sandbox Code Playgroud)

理论

我相信错误以某种方式与 aJax 相关联,我也在控制器中像这样创建按钮。 "<button type='button' class='btn btn-warning' onclick='ExportToExcel(" + c.id + ");'>Print</button>",

由于location.href='@Url.Action有效,我想知道尝试重做我的动态按钮是否会解决我的问题。

欣赏可以提供的任何见解。

Abh*_*hek 5

是的,您是对的,您遇到了 ajax 问题,基本上,当您的第一个 ajax 调用返回成功时,您必须再次从 ajax 调用中调用控制器操作。将以下代码片段添加到您的 ajax 调用中。

success: function () {

    window.location = '@Url.Action("ExportExcel", "Profile")?id='+id;
}
Run Code Online (Sandbox Code Playgroud)

并且您必须更改控制器方法以返回文件,如下所示

public FileResult ExportToExcelx()
{
	...............
	
	byte[] byteArray = Encoding.ASCII.GetBytes(sw.ToString());
	return File(byteArray, System.Net.Mime.MediaTypeNames.Application.Octet, "FileName.xlsx");                       
}
Run Code Online (Sandbox Code Playgroud)


小智 0

首先,我不会使用GridView来生成excel。尽管很“简单”,但它不会生成实际的 Excel 文件,而是生成带有 xls 扩展名的 html 文件:

<div>
    <table cellspacing="0" rules="all" border="1" style="border-collapse:collapse;">
        <tr>
            <th scope="col">col1</th><th scope="col">col2</th>
        </tr><tr>
            <td>1</td><td>product 1</td>
        </tr><tr>
            <td>2</td><td>product 2</td>
        </tr><tr>
            <td>3</td><td>product 3</td>
        </tr><tr>
            <td>4</td><td>product 4</td>
        </tr><tr>
            <td>5</td><td>product 5</td>
        </tr><tr>
            <td>6</td><td>product 6</td>
        </tr><tr>
            <td>7</td><td>product 7</td>
        </tr>
    </table>
</div>
Run Code Online (Sandbox Code Playgroud)

这会产生一个文件,打开时会导致以下情况: Excel打开html表格时出错

这很烦人(而且不专业)。如果您不受旧 excel 版本 - xls - 但可以使用最新的文件格式 xlsx,我宁愿使用 DocumentFormat.OpenXml nuget 包或其他包/库来生成 excel。老实说,DocumentFormat.OpenXml 功能强大,但使用起来有点无聊,当您有很多列并且只有一个要报告的对象的平面列表时。如果您使用 .NET Framework(不是 Dotnet Core),您可以尝试 CsvHelper.Excel nuget 包。用法非常简单。您的 ExportToExcel 方法将类似于:

public ActionResult ExportToExcel(string id)
{
    // TODO: Replace with correct products retrieving logic using id input
    var products = new [] {
       { col1 = 1, col2 = "product 1" },
       { col1 = 2, col2 = "product 2" },
       { col1 = 3, col2 = "product 3" },
       { col1 = 4, col2 = "product 4" },
       { col1 = 5, col2 = "product 5" },
       { col1 = 6, col2 = "product 6" },
       { col1 = 7, col2 = "product 7" },
       { col1 = 1, col2 = "product 1" },
       { col1 = 1, col2 = "product 1" },
    };

    var ms = new MemoryStream();
    var workbook = new XLWorkbook();
    using (var writer = new CsvWriter(new ExcelSerializer(workbook)))
    {
       writer.WriteRecords(products);
    }
    workbook.SaveAs(ms);
    ms.Flush();
    ms.Seek(0, SeekOrigin.Begin);
    return File(ms, MimeMapping.GetMimeMapping("file.xlsx"), $"MyExcelFile.xlsx");

}
Run Code Online (Sandbox Code Playgroud)

另一个非常强大的软件包是 EPPlus,它允许您加载数据表(请参阅:https: //stackoverflow.com/a/53957999/582792)。

来到 AJAX 部分,嗯...我认为您根本不需要它:一旦您将位置设置为新的 ExportToExcel 操作,它应该只下载文件。假设您使用 Bootstrap 3,对于集合中的每个项目,您可以:

<a href="@Url.Action("ExportToExcel", "Profile", new {id=item.Id})" class="btn btn-info">
<i class="glyphicon glyphicon-download-alt" />
</a>
Run Code Online (Sandbox Code Playgroud)