2011-01-07 13 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?