[ASP.net/MSSQL] 讀寫Office Excel之前要做的相關設定

[ASP.net/MSSQL] 讀寫Office Excel之前要做的相關設定

2013.5.14 追記黑暗執行緒的一篇好文:透過.NET程式操作Excel的注意事項

 

網站跑的是.net Framework 4 ,WebServer電腦沒有灌Microsoft Excel軟體

ASP.net程式在宣告以下的變數時:


    Microsoft.Office.Interop.Excel.Application xlApp = null;
    Workbook wb = null;
    Worksheet ws = null;
    Range aRange = null;

 

會跑出錯誤

The resource cannot be found.

所以要用ASP.net程式讀寫Excel的話

得先做以下設定

Step 1. 正式機Server的電腦要先灌Microsoft Excel軟體(否則會錯誤The resource cannot be found.)

Step 2. 接著做以下設定,否則仍會發生

System.NullReferenceException: 並未將物件參考設定為物件的執行個體
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
 
由於發生下列錯誤,為具有 CLSID {00024500-0000-0000-C000-000000000046} 的元件擷取 COM Class Factory 失敗: 80070005。
描述: 在執行目前 Web 要求的過程中發生未處理的例外情形。請檢閱堆疊追蹤以取得錯誤的詳細資訊,以及在程式碼中產生的位置。

例外詳細資訊: System.UnauthorizedAccessException: 由於發生下列錯誤,為具有 CLSID {00024500-0000-0000-C000-000000000046} 的元件擷取 COM Class Factory 失敗: 80070005。

沒有授權 ASP.NET 存取要求的資源。請考慮將資源存取權授與 ASP.NET 要求識別。ASP.NET 有一個基本處理序識別 (通常在 IIS 5 上為 {MACHINE}\ASPNET,在 IIS 6 上為 Network Service),會在應用程式未模擬的情況下使用。如果應用程式是透過 <identity impersonate="true"/> 模擬,這個識別將會是匿名使用者 (通常為 IUSR_MACHINENAME) 或經過驗證的要求使用者。

若要對檔案授與 ASP.NET 存取權,請在檔案總管中以滑鼠右鍵按一下檔案,選擇 [內容] 並選取 [安全] 索引標籤。按一下 [新增] 加入適當的使用者或群組。反白顯示 ASP.NET 帳戶,並且選取所需存取權限的核取方塊。

 

(Windows Server 2003 範例)

由系統管理工具>元件服務>電腦>我的電腦>DCOM設定>在右方找到Microsoft Excel應用程式(Application)

001

右鍵>內容>頁籤安全設定

點選啟動和啟用權限>編輯

002

因為是IIS 6,所以新增一個Network Service帳戶,且四個權限全部勾選

Server電腦到此設定完畢,另外

解決Win2008 Asp.NET使用Word.Selection會有System.NullReferenceException的問題 - 亂馬客- 點部落

的文章有提到識別身份(識別碼),要再選擇「互動式使用者」,這邊我是保持預設設定「執行啟動的使用者」仍然還是可以Run的。

Step 3.為網站專案加入COM參考(Visual Studio中,專案右鍵>加入參考)

  • 視Server安裝的 Office 版本而定,Excel 組件可能會稱為 [Excel 10 物件程式庫] 或 [Excel 11 物件程式庫(Office 2007)]。

    參考來源:MSDN文件 HOW TO:使用 COM Interop 來建立 Excel 試算表 (C#)

    Step 4.為網站專案加入.NET參考(Visual Studio中,專案右鍵>加入參考)

    12.0.0.0為2007版本,14.0.0.0為2010版本,同時加兩個dll的話,網站執行會錯誤,或電腦上已安裝了某版本Office,網站又加入參考而發生以下錯誤的話
    CS1758: Cannot embed interop type 'Microsoft.Office.Interop.Excel.Constants' found in both assembly 'c:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\網站名稱\a43c6b27\e0d3dd6d\assembly\dl3\6741d390\004ce13f_fab6cb01\Microsoft.Office.Interop.Excel.DLL' and 'c:\WINDOWS\assembly\GAC\Microsoft.Office.Interop.Excel\12.0.0.0__71e9bce111e9429c\Microsoft.Office.Interop.Excel.dll'. Consider setting the 'Embed Interop Types' property to false. An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

    解決辦法:

    1.先把網站Bin目錄底下的

    Microsoft.Office.Interop.Excel.dll和xml、Microsoft.Vbe.Interop.dll、office.dll和xml都刪掉

    2.到IIS管理員停止IIS 網際網路服務

    3.刪除Server電腦 C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET Files\網站名稱\(此資料夾底下所有檔案)
    (請注意.net framework版本不同,目錄也不同)

    4.再重新啟動IIS 網際網路服務就可以了

     

    網站設定這樣就完畢,ASP.net程式應該可以讀寫Excel檔案了。

    2011.5.19 追記,Windows Server 2008 除了以上設定外,要再加以下的設定

    否則會

    Microsoft Office Excel 無法存取檔案 'D:\1cd.xls'。可能原因如下:

    ‧檔案的名稱或路徑不存在。
    ‧這個檔案正被其他程式所使用中。
    ‧您要儲存的活頁簿名稱與現有開啟的活頁簿名稱相同。
    描述: 在執行目前 Web 要求的過程中發生未處理的例外情形。請檢閱堆疊追蹤以取得錯誤的詳細資訊,以及在程式碼中產生的位置。

    例外詳細資訊: System.Runtime.InteropServices.COMException: Microsoft Office Excel 無法存取檔案 'D:\1cd.xls'。可能原因如下:

    ‧檔案的名稱或路徑不存在。
    ‧這個檔案正被其他程式所使用中。
    ‧您要儲存的活頁簿名稱與現有開啟的活頁簿名稱相同。


    1. Web.config裡,加入<identity />區段,登入Server電腦的帳密

    2. 在C:\Windows\System32\config\systemprofile\底下建「Desktop」資料夾

    詳細來源:呆奇士 WinServer2008 & IIS & Excel - 無法存取檔案


    最後

    當然如果你的ASP.net 程式是跑在自己電腦上,自己的電腦又已經灌了Microsoft Excel軟體,就不用做以上繁雜的設定



    2011.6.17 追記

    今天在Windows Server 2008 R2 (它只有64位元版本)的環境上部署Web site

    先灌了Excel 2003軟體,但執行到Excel匯入程式時出現以下錯誤


    Compilation Error

    Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately.

    Compiler Error Message: CS1758: Cannot embed interop type 'Microsoft.Office.Interop.Excel.Constants' found in both assembly 'c:\Windows\Microsoft.NET\Framework64\v4.0.30319\Temporary ASP.NET Files\blood_intra\c1a2dcd7\cd772699\assembly\dl3\da3f232c\001fb03e_fab6cb01\Microsoft.Office.Interop.Excel.DLL' and 'c:\Windows\assembly\GAC\Microsoft.Office.Interop.Excel\11.0.0.0__71e9bce111e9429c\Microsoft.Office.Interop.Excel.dll'. Consider setting the 'Embed Interop Types' property to false.



    以上訊息大致說Web site引用的參考檔案和Server上灌的Excel軟體的Excel.dll檔互衝

    解決方式:
    把Web site>Bin資料夾底下

    Microsoft.Office.Interop.Excel.dll和xml、Microsoft.Vbe.Interop.dll、office.dll和xml
    Excel相關參考檔案都刪除

    讓Web site自己去抓Server上的Excel.dll即可。


    但後來再執行程式出現object reference not set to an instance of an object 的錯誤訊息(真是鬼打牆= =

    本來想照著以上說明去「元件服務」設定DCOM元件,結果發現竟然沒有Microsoft Excel Application(汗

    忽然想起來這是64位元的作業系統,我灌的是32位元的Excel軟體…Orz

    後來照著呆奇士 WinServer2008 & IIS & Excel - 無法存取檔案 裡頭文章所講

    設定Web.config檔的<identity>區段和新增資料夾C:\Windows\SysWOW64\config\systemprofile\Desktop

    才終於成功
     


    ※2012.10.17 追記[元件服務]在x64系統無法看見Microsoft Excel Application的問題:http://www.dotblogs.com.tw/gelis/archive/2010/12/25/20381.aspx

    2011.6.17 再追記 SQL Server 2008 (64位元) 如何新增一個Office Excel Driver:

    如果是Windows Server 2008 R2(64位元)上的SQL Server 2008 (64位元),會發現無論怎麼灌Office Excel,連結伺服器的提供者都不會出現Excel相關Driver

    那是因為目前的Office軟體大都是32位元,SQL Server 2008 (64位元)不支援的關係

    解決方法:

    Microsoft下載中心 下載Microsoft Access Database Engine 2010 可轉散發套件(挑最新版就好)

    因為環境都是64位元,所以要下載AccessDatabaseEngine_X64.exe,這個檔案

    然後安裝前,如果有先灌好Office 32位元軟體的話,程式會要求你先解除安裝,就先解除Office軟體後,再安裝AccessDatabaseEngine_X64.exe這個檔案

    連結伺服器的提供者就會出現一個Microsoft.ACE.OLEDB.12.0可以撈Excel資料(而且SQL Server上不用灌Office Excel軟體)

    MSDN的討論:如何新增連結伺服器的提供者

    2011.6.20 追記環境設定

    如何在Windows Server 2008 R2環境下,使用SQL Server 帳戶(sa)連線的ASP.net程式,下OpenRowSet語法指令匯入資料

    DB Server和Web Server兩台作業系統都是Windows Server 2008 R2

    1.兩台作業系統都新增相同的帳戶、相同的密碼(範例帳戶HelloWorld,密碼:HelloWorld,系統管理員):



    2. 新增完後對Web Site的Web.config檔新增<identity>區段,如下:

    <identity impersonate="true" userName="HelloWorld" password="HelloWorld"   />

    3.在DB機器的C:\底下新增一個分享資料夾(範例:aspUpload)



    安全性加入一個Everyone,完全控制


    該資料夾點選共用:


    共用加入Everyone:


    如此一來,共用的「進階共用」的權限應該就會多一個Everyone的權限

    環境設定完畢,就著就可以寫Code了

     

        //Click按鈕事件
        protected void btn_Click(object sender, EventArgs e)
        {
            //檔案上傳到DB Server機器上
            fu.SaveAs(@"\\192.168.1.110\aspUpload\" + fu.FileName);
            DBUtil db = new DBUtil();//這是用sa登入的資料庫連線物件

            //SQL Server 撈本機路徑的資料
            DataTable dt = db.QueryDataTable(@"SELECT a.* from
                                               OPENROWSET('Microsoft.ACE.OLEDB.12.0','Excel 12.0;HDR=yes;IMAX=1;Database=C:\aspUpload\" + fu.FileName + @"',[Sheet1$]) a");

            //GridView控制項呈現資料 - Debug用
            gv.DataSource = dt;
            gv.DataBind();

        }

    參考Windows Server 2003的設定:
    1.How to : 如何將使用者利用ASP.NET程式上傳的檔案傳送到另一台電腦中(不透過FTP)
    2.ASP.NET 如何將檔案寫入到網路芳鄰的分享目錄
    對照以上兩篇文章,我沒有在Web Server新增虛擬目錄
    也沒有在WebServer的C:\WINDOWS\Microsoft.NET\Framework(和64)\v2.0.50727(和v4.xx版)\Temporary ASP.NET Files資料夾設定權限

    2011.7.16 上述程式碼做法是把檔案先上傳到DB Server機器,這邊再提供一個用sa撈AP Server機器上檔案的方法

    Step 1. AP Server端的資料夾要先做共用分享(假設everyone、讀寫都可以)

    Step 2. DB Server端和AP Server端電腦都要有相同的Windows帳密(沒有的話就新增一個,假設 MyAccount/P@ssw0rd)

    Step 3. 最重要的是以下這張圖



     

    (這邊用個人的測試環境Demo)把SQL Server的服務登入帳戶改成MyAccount/P@ssw0rd就可以了。

    附上MSDN論壇的討論:Win2008 R2+SQL2008 R2 使用sa帳戶下OPENROWSET撈不到另一台機器上的資料