2011-01-07 53 views
0

我有一个现有的delphi桌面应用程序,我改写为一个asp.net mvc应用程序。如何从asp.net mvc更新和保存excel文件?

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

产生对桌面应用的报告,我使用OLE自动化

  1. 打开报告
  2. 填入命名的单元格与正确的数据
  3. 使用ActiveWorkbook.RefreshAll()来 更新查询和数据透视表
  4. 保存报告

我想这样做以米y Web应用程序。然而,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); 

在dev的机器,它工作正常,但是在服务器上它在第一行

objApp = new Application(); 

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

回答

0

你是对的,它绝对不支持MS。然而,ole自动化应该在服务器上工作。这是一个愚蠢的问题,你有没有在服务器上安装Excel?你能发送你的示例代码吗? 我通常使用interop。这里是一个简单的例子:http://dotnetperls.com/excel

4

我还没有与图表合作过,但我彻底推荐了EPPlus这是一个用于创建Excel工作簿的开源库。

+0

Upvote on EPPlus。很棒的图书馆,但是我已经能够找出有限的数据透视表支持。 – iivel 2011-02-28 21:30:34

5

这是一个很常见的错误,但需要在服务器上设置一些项目才能与ASP.NET一起使用。一般来说,这个线程上的建议就足够了:System.UnauthorizedAccessException: Retrieving the COM class factory for Word Interop fails with error 80070005.

这似乎并没有得到妥善和彻底的处理。迟绑定也可能是问题的一部分。

+0

我已经通过这些链接,但我仍然有错误。 我正在使用IIS 7.0。我已经为网络服务和IIS_IUSRS设置了dcom Excel.Application权限。仍然没有快乐。 – SeanX 2011-02-24 00:36:04

+0

我在服务器上运行excel 2003,在我的机器上运行2007。不过,我已经重写我的代码以使用后期绑定。测试.net应用程序可以加载和更新excel。 Asp仍然不能:(。 – SeanX 2011-02-27 20:39:02

+0

答案不是什么提问者正在寻找,所以编辑它。 – 2011-03-01 16:04:19

2

看看NPOI

+0

看起来不像我可以刷新现有的报告。 – SeanX 2011-02-27 19:38:42

1

你是对的,你可能不希望做的OLE自动化服务器上​​。只是存在内存泄漏和在后台运行非托管的Excel实例的风险是不可行的。

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

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();` 
1

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

这里是一个详细的解决方案,为我工作:http://blog.crowe.co.nz/archive/2006/03/02/589.aspx

希望这有助于。

PS:那OLE DB,是有可能改变你的代码使用的OleDbConnection?