如何从asp.net mvc更新和保存excel文件?

时间:2011-01-07 03:33:36

标签: asp.net asp.net-mvc excel

我有一个现有的delphi桌面应用程序,我将其重写为asp.net mvc应用程序。

桌面应用程序有大约120个excel报告。这些报告通常包含很少的命名单元格,其中包含设置信息(客户端ID等),一些数据查询返回到sql server数据和几个关键表。

要在桌面应用上生成报告,我使用ole automation

  1. 打开报告
  2. 使用正确的数据填充命名的单元格
  3. 使用ActiveWorkbook.RefreshAll()来 更新查询和数据透视表
  4. 保存报告
  5. 我想在我的网络应用程序中执行此操作。但是,在服务器上不支持ole自动化,并且不起作用。我见过的所有excel组件似乎都不支持刷新查询和/或关键表。

    目前,我最好的选择似乎是使用某些报表生成器重写报表并将这些报表导出到Excel。但是,生成的文件需要更长的时间来编写,功能更少(没有关键表),当然还有120个。

    有关如何使用现有报告的任何建议?

    更新

    Excel安装在服务器上,与开发机器上的版本相同。

    我的mvc代码类似于:

    objApp = new Application();
    objBooks = objApp.Workbooks;
    objBook = objBooks.Open(FileName);
    objApp.DisplayAlerts = false;  // don't warn if pivot table changed
    objApp.ActiveWorkbook.RefreshAll();
    objBook.SaveAs(newFileName);
    

    在开发机器上它工作正常,但在服务器上它在第一行失败

    objApp = new Application();
    

    与 System.UnauthorizedAccessException:由于以下错误,检索CLSID为{00024500-0000-0000-C000-000000000046}的组件的COM类工厂失败:80070005拒绝访问。 (HRESULT异常:0x80070005(E_ACCESSDENIED))。

7 个答案:

答案 0 :(得分:5)

这是一个非常常见的错误,但需要在服务器上设置许多项目才能与ASP.NET一起使用。通常,此主题的建议就足够了:System.UnauthorizedAccessException: Retrieving the COM class factory for Word Interop fails with error 80070005.

似乎没有正确彻底地处理这些问题。延迟绑定也可能是问题的一部分。

答案 1 :(得分:4)

我没有使用过图表,但我完全推荐使用EPPlus这是一个用于创建Excel工作簿的开源库。

答案 2 :(得分:2)

查看NPOI

答案 3 :(得分:1)

你是对的,你可能不想在服务器上进行OLE自动化。只是存在内存泄漏和后台运行不受管理的Excel实例的风险是不行的。

我们对Aspose.Cells有很好的经验。也许它支持您正在寻找的刷新功能?

答案 4 :(得分:1)

我几个月前发现这个类我用来写excel而不使用excel。它就像一个魅力,我在很多ASP.net应用程序中使用它。老实说,我不记得我从哪里得到它,所以即使他们应得的一切,我也不能给那个人创造。

/// <summary>
/// Produces Excel file without using Excel
/// </summary>
public class ExcelWriter
{
private Stream stream;
private BinaryWriter writer;

private ushort[] clBegin = { 0x0809, 8, 0, 0x10, 0, 0 };
private ushort[] clEnd = { 0x0A, 00 };


private void WriteUshortArray(ushort[] value)
{
    for (int i = 0; i < value.Length; i++)
        writer.Write(value[i]);
}

/// <summary>
/// Initializes a new instance of the <see cref="ExcelWriter"/> class.
/// </summary>
/// <param name="stream">The stream.</param>
public ExcelWriter(Stream stream)
{
    this.stream = stream;
    writer = new BinaryWriter(stream);
}

/// <summary>
/// Writes the text cell value.
/// </summary>
/// <param name="row">The row.</param>
/// <param name="col">The col.</param>
/// <param name="value">The string value.</param>
public void WriteCell(int row, int col, string value)
{
    ushort[] clData = { 0x0204, 0, 0, 0, 0, 0 };
    int iLen = value.Length;
    byte[] plainText = Encoding.ASCII.GetBytes(value);
    clData[1] = (ushort)(8 + iLen);
    clData[2] = (ushort)row;
    clData[3] = (ushort)col;
    clData[5] = (ushort)iLen;
    WriteUshortArray(clData);
    writer.Write(plainText);
}

/// <summary>
/// Writes the integer cell value.
/// </summary>
/// <param name="row">The row number.</param>
/// <param name="col">The column number.</param>
/// <param name="value">The value.</param>
public void WriteCell(int row, int col, int value)
{
    ushort[] clData = { 0x027E, 10, 0, 0, 0 };
    clData[2] = (ushort)row;
    clData[3] = (ushort)col;
    WriteUshortArray(clData);
    int iValue = (value << 2) | 2;
    writer.Write(iValue);
}

/// <summary>
/// Writes the double cell value.
/// </summary>
/// <param name="row">The row number.</param>
/// <param name="col">The column number.</param>
/// <param name="value">The value.</param>
public void WriteCell(int row, int col, double value)
{
    ushort[] clData = { 0x0203, 14, 0, 0, 0 };
    clData[2] = (ushort)row;
    clData[3] = (ushort)col;
    WriteUshortArray(clData);
    writer.Write(value);
}

/// <summary>
/// Writes the empty cell.
/// </summary>
/// <param name="row">The row number.</param>
/// <param name="col">The column number.</param>
public void WriteCell(int row, int col)
{
    ushort[] clData = { 0x0201, 6, 0, 0, 0x17 };
    clData[2] = (ushort)row;
    clData[3] = (ushort)col;
    WriteUshortArray(clData);
}

/// <summary>
/// Must be called once for creating XLS file header
/// </summary>
public void BeginWrite()
{
    WriteUshortArray(clBegin);
}

/// <summary>
/// Ends the writing operation, but do not close the stream
/// </summary>
public void EndWrite()
{
    WriteUshortArray(clEnd);
    writer.Flush();
}
}

只需将此代码复制到.cs文件中即可。

这是一个例子

    ExcelWriter writer = null;
    FileStream stream = null;
    string result = string.Empty;

        string filepath = path;
        DateTime sd = Convert.ToDateTime(sdate);
        DateTime ed = Convert.ToDateTime(edate);
        string daterange = sd.Month.ToString() + sd.Day.ToString() + sd.Year.ToString() + "_" + ed.Month.ToString() + ed.Day.ToString() + ed.Year.ToString();
        string xls = filepath + filename + "_" + daterange + ".xls";

        if (File.Exists(xls))
        {
            File.Delete(xls);
        }

        stream = new FileStream(xls, FileMode.Create);
        writer = new ExcelWriter(stream);
        writer.BeginWrite();

        //write header

        writer.WriteCell(0, 0, "text");
        writer.WriteCell(0, 1, "text");
        writer.WriteCell(0, 2, "text");


        //write data
        int row = 1;

        //Open Connection
        OpenDBConnection();

        //get Case List
        List<Int32> caseList = getCaseList(sdate, edate);

        foreach (Int32 caseid in caseList)
        {
            writer.WriteCell(row, 0, caseid);
            writer.WriteCell(row, 1, caseid);
            writer.WriteCell(row, 2, caseid);
            row++;
        }

        writer.EndWrite();
        stream.Close();`

答案 5 :(得分:1)

可能你遇到了几个月前的问题。问题是默认情况下,Microsoft Excel作为COM对象只能由管理员,系统或交互式帐户激活。

这是一个详细的解决方案,对我有用:http://blog.crowe.co.nz/archive/2006/03/02/589.aspx

希望这有帮助。

ps:OLE DB怎么样,是否可以更改代码以使用OleDbConnection?

答案 6 :(得分:0)

你是对的,MS肯定不支持。但是,ole自动化应该在服务器上运行。这是一个愚蠢的问题,你在服务器上安装了Excel吗?你能发送样品代码吗? 我通常使用interops。这是一个简单的例子:http://dotnetperls.com/excel