如何导出到Excel?

时间:2015-09-29 07:11:02

标签: c# asp.net asp.net-mvc excel asp.net-mvc-5

我跟着this guide,这是在另一篇文章中推荐的,但我无法让它发挥作用。尝试重定向到/ LogModelsController / ExportData时出现404错误 - 正如我所理解的那样 - 是我本应该做的。

_LogPartialLayout.cshtml

@using (Html.BeginForm("ExportData", "LogModelsController", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
    <table class="table">
        <tr>
            <th>
                @Html.ActionLink("message", "Index", new { sortOrder = ViewBag.NameSortParm, currentFilter = ViewBag.CurrentFilter })

            </th>
            <th>
                @Html.ActionLink("timestamp", "Index", new { sortOrder = ViewBag.NameSortParm, currentFilter = ViewBag.CurrentFilter })
            </th>
            <th>
                @Html.ActionLink("level", "Index", new { sortOrder = ViewBag.NameSortParm, currentFilter = ViewBag.CurrentFilter })
            </th>

        </tr>

        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.message)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.timeStamp)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.level)
                </td>
            </tr>
        }
    </table>
    <input type="submit" name="Export" id="Export" value="Export" />
}

_LogPartialLayout.cshtml

LogModelsController.cs

public ActionResult ExportData()
        {
            GridView gv = new GridView();
            gv.DataSource = db.Log.ToList();
            gv.DataBind();
            Response.ClearContent();
            Response.Buffer = true;
            Response.AddHeader("content-disposition", "attachment; filename=Loglist.xls");
            Response.ContentType = "application/ms-excel";
            Response.Charset = "";
            StringWriter sw = new StringWriter();
            HtmlTextWriter htw = new HtmlTextWriter(sw);
            gv.RenderControl(htw);
            Response.Output.Write(sw.ToString());
            Response.Flush();
            Response.End();

            return RedirectToAction("~/LogModels/Index");
        }

LogModel.cs

namespace ASDMVC.Models
{
    [Table("Log")]
    public class LogModel
    {
        [Key]
        public long id { get; set; }
        public string message { get; set; }
        public DateTime timeStamp { get; set; }
        public string level { get; set; }
        public int customerId { get; set; }
    }

    public class LogDBContext:DbContext
    {
        public LogDBContext() : base("MySqlConnection")
        {

        }

        public DbSet <LogModel> Log { get; set; }

    }
}

TD; DR:如何将此表正确导出到Excel?

Bonus:它也适用于PagedList吗?

编辑3 - 已解决

Index.cshtml:

@using (Html.BeginForm("ExportData", "LogModels"))
{
    <input type="submit" name="Export" id="Export" value="Export" />
}

LogModelsController.cs

public ActionResult ExportData()
{
    DataTable dataTable = GetData();

    using (ExcelPackage package = new ExcelPackage())
    {
        var ws = package.Workbook.Worksheets.Add("My Sheet");
        //true generates headers
        ws.Cells["A1"].LoadFromDataTable(dataTable, true);

        var stream = new MemoryStream();
        package.SaveAs(stream);

        string fileName = "myfilename.xlsx";
        string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

        stream.Position = 0;
        return File(stream, contentType, fileName);
    }
}

public DataTable GetData()
{
    DataTable dt = new DataTable();
    if (ModelState.IsValid)
    {
        using (SqlConnection conn = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MySqlConnection"].ConnectionString))
        {
            using (SqlCommand comm = conn.CreateCommand())
            {
                comm.Parameters.AddWithValue("@val1", Session["myID"]);
                comm.CommandText = "SELECT * FROM dbo.Log WHERE CustomerId = @val1";
                try
                {
                    conn.Open();
                    dt.Load(comm.ExecuteReader());
                }
                catch (SqlException e)
                {
                    throw new Exception(e.ToString());
                }
            }
        }
    }
    return dt;
}

我在CommandText中犯了一个错误并输入“Id”而不是“CustomerId” - 它现在返回Excel文件中的整个表。

3 个答案:

答案 0 :(得分:4)

该指南未显示如何创建Excel文件,它显示了一个使用Table创建HTML文件的hack。 Excel将尝试使用默认设置导入带有表的csv或HTML文件,这些设置通常会失败。

使用像EPPlus这样的库创建正确的 Excel文件要容易得多。 我确定之前已经回答了这个问题,但我找不到一个答案,其中显示了如何create an Excel file from data并为xlsx文件设置了proper content type

EPPlus提供了LoadFromDataTable和LoadFromCollection方法,用于从DataTable或通用集合中提取数据来填充Excel范围。列或属性名称分别用作标题。

public ActionResult ExportData()
{

    //Somehow, load data to a DataTable

    using (ExcelPackage package = new ExcelPackage())
    {
        var ws = package.Workbook.Worksheets.Add("My Sheet");
        //true generates headers
        ws.Cells["A1"].LoadFromDataTable(dataTable, true);

        var stream = new MemoryStream();
        package.SaveAs(stream);

        string fileName = "myfilename.xlsx";
        string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

        stream.Position = 0;
        return File(stream, contentType, fileName);
    }
}

LoadFromDataTable或LoadFromCollection返回一个Excel单元格区域,可用于格式化表格:

var range=ws.Cells["A1"].LoadFromDataTable(table);
range.Style.Numberformat.Format = "#,##0.00";
range.Style.HorizontalAlignment = ExcelHorizontalAlignment.Right;

您还可以将范围样式应用于范围,或将所需的样式传递给LoadFromDataTableLoadFromCollection,例如:

ws.Cells[1,1].LoadFromDataTable(table, true, TableStyles.Light1);

图书馆的Githup wiki显示如何format the result,生成公式,数据透视表,处理表等。

如果要创建相对较大的工作表,则保存到MemoryStream可能会出现问题。将相同的数据写入两次,一次写入MemoryStream然后将其复制到输出,会浪费周期。直接写入MVC动作的输出流是一种不好的做法。诀窍是创建一个自定义的FileResult来处理EPPlus包并返回它而不是File返回的FileResult,例如:

public class EpplusResult:FileResult
{
    public EpplusResult(ExcelPackage package)
        : base("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
    {
        if (package == null)
        {
            throw new ArgumentNullException("package");
        }

        Package = package;
    }

    public ExcelPackage Package { get; private set; }

    protected override void WriteFile(HttpResponseBase response)
    {
        // grab chunks of data and write to the output stream
        Stream outputStream = response.OutputStream;
        using (Package)
        {
            Package.SaveAs(outputStream);
        }
    }
}

允许您编写以下操作:

public FileResult ExportData()
{

    ExcelPackage package = new ExcelPackage();
    var ws = package.Workbook.Worksheets.Add("My Sheet");       
    ...
    ws.Cells[1,1].LoadFromDataTable(table, true, TableStyles.Light1);

    return new EpplusResult(package){FileDownloadName = "SomeFile.xlsx"};
}

答案 1 :(得分:2)

不要创建基于HTML的Excel文件,它们有很多问题。

Insteed使用紧凑的库,例如epplus

public ActionResult ExportData()
{

    using (ExcelPackage package = new ExcelPackage())
    {
        var ws = package.Workbook.Worksheets.Add("LogMessages");
       //Headers
        ws.Cells["A1"].Value = "Message";
        ws.Cells["B1"].Value = "TimeStamp";
        ws.Cells["C1"].Value = "Level";


       var rowNumber=1;

        foreach (var log in DbContext.Log)
       {
           ws.Cells[rowNumber, 1].Value = vehicle.message;
           ws.Cells[rowNumber, 2].Value = vehicle.timeStamp;
           ws.Cells[rowNumber, 3].Value = vehicle.level;
           rowNumber++;
       }


        var stream = new MemoryStream();
        package.SaveAs(stream);

        string fileName = "logMessags.xlsx";
        string contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

        stream.Position = 0;
        return File(stream, contentType, fileName);
    }
}

我使用Panagiotis Kanavos代码结构来实现此解决方案

答案 2 :(得分:0)

检查一下,这个库包含一个ExcelResult,它将自动创建过程,并通过调用Excel()方法将Excel文件发送到客户端,就像Json()一样。

https://github.com/iabdelkareem/MVC-Excel-Extensions

相关问题