2012-04-11 99 views
1

我有一個問題,起初似乎是許可。 在localhost工作恰到好處,但是當進入到一個服務器出現錯誤:如何在C#中使用Word文檔#

[UnauthorizedAccessException: Retrieving the COM class factory for component with CLSID {000209FF-0000-0000-C000-000000000046} failed due to the Following error: 80070005.]

我用IIS7
我給了允許IIS用戶,但無濟於事,於是我上鋪的代碼「嘗試捕獲」並發現該錯誤與目前它試圖創建的Microsoft.Office.Interop.Word

的實例

例如

using Word = Microsoft.Office.Interop.Word; 

private bool Exemple(SqlDataReader dbReader, string strFilePath) 
{ 
    Word.Application oApp = new Word.Application(); // error here 
    ... 
    ... 
    ... 
} 

的Microsoft.Office.Interop.Word這個DLL的SERV的Bin文件夾呃,有沒有人知道可能會發生什麼?

謝謝。

+0

咦?您的服務器是否安裝了Word? – KingCronus 2012-04-11 14:26:57

+0

從客戶端檢查服務,可能是訪問權限問題 – Likurg 2012-04-11 14:29:53

+2

您不應將Office interop庫用於服務器應用程序。它違反了微軟的建議,因爲可能會有僵局和其他不愉快的事情,會完全阻礙你的應用程序。 – Leonard 2012-04-11 14:31:50

回答

4

雖然您不應該在服務器上使用Office互操作庫。微軟不建議或支持這種實現,但如果您要求懲罰以避免出現錯誤,則需要在服務器上打開DCOM配置並將身份設置爲您的應用程序池正在運行的用戶,並授予他們訪問啓動和激活權限。再次,您不想在服務器上設置Office互操作庫。

0

(雖然不建議使用Office互操作在服務器上,但有時我們不得不...)

問題是關係到安全性。 ASP.NET進程的用戶身份沒有使用Office應用程序的訪問權限,並且身份應該只具有運行應用程序所需的最低權限。您可以使用代碼模擬在運行時提高權限,而無需在web.config中設置模擬或爲我的ASP.NET用戶帳戶使用高特權帳戶。我已經在服務器上使用它,我喜歡這種方法。

您可以通過google瞭解更多。 下面是從http://support.microsoft.com/kb/306158的代碼:

public class CodeImpersonate 
{ 
    /// <summary> 
    /// This logon type is intended for users who will be interactively using the computer, such as a user being logged on by a terminal server, 
    /// remote shell, or similar process. This logon type has the additional expense of caching logon information for disconnected operations; therefore, 
    /// it is inappropriate for some client/server applications, such as a mail server. 
    /// </summary> 
    public const int LOGON32_LOGON_INTERACTIVE = 2; 
    /// <summary> 
    /// Use the standard logon provider for the system. The default security provider is negotiate, 
    /// unless you pass NULL for the domain name and the user name is not in UPN format. In this case, the default provider is NTLM. 
    /// Windows 2000: The default security provider is NTLM. 
    /// </summary> 
    public const int LOGON32_PROVIDER_DEFAULT = 0; 

    WindowsImpersonationContext impersonationContext; 

    [DllImport("advapi32.dll")] 
    public static extern int LogonUserA(String lpszUserName, 
             String lpszDomain, 
             String lpszPassword, 
             int dwLogonType, 
             int dwLogonProvider, 
             ref IntPtr phToken); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken); 

    [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    public static extern bool RevertToSelf(); 

    [DllImport("kernel32.dll", CharSet = CharSet.Auto)] 
    public static extern bool CloseHandle(IntPtr handle);  

    public bool ImpersonateValidUser(String userName, String domain, String password) 
    { 
     WindowsIdentity tempWindowsIdentity; 
     IntPtr token = IntPtr.Zero; 
     IntPtr tokenDuplicate = IntPtr.Zero; 

     if (RevertToSelf()) 
     { 
      if (LogonUserA(userName, domain, password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref token) != 0) 
      { 
       if (DuplicateToken(token, 2, ref tokenDuplicate) != 0) 
       { 
        tempWindowsIdentity = new WindowsIdentity(tokenDuplicate); 
        impersonationContext = tempWindowsIdentity.Impersonate(); 
        if (impersonationContext != null) 
        { 
         CloseHandle(token); 
         CloseHandle(tokenDuplicate); 
         return true; 
        } 
       } 
      } 
     } 
     if (token != IntPtr.Zero) 
      CloseHandle(token); 
     if (tokenDuplicate != IntPtr.Zero) 
      CloseHandle(tokenDuplicate); 
     return false; 
    } 

    public void UndoImpersonation() 
    { 
     if (impersonationContext != null) 
      impersonationContext.Undo(); 
    } 

}

複製一個文件中的上述代碼。下面是一個示例使用它:

CodeImpersonate codeImpersonate = null; 
try 
{ 
    codeImpersonate = new CodeImpersonate(); 
    var isLoggedIn = codeImpersonate.ImpersonateValidUser(AppConfigs.OfficeUser, AppConfigs.OfficeUeerDomnia, AppConfigs.OfficeUserPass); 

    if (isLoggedIn) 
    { 
     //Do your office work.... 
    } 
    else 
     throw new InvalidOperationException("Login failed for office user."); 
} 
finally 
{ 
    if (codeImpersonate != null) 
     codeImpersonate.UndoImpersonation(); 
    codeImpersonate = null; 
} 

要在幾個地方使用上面的代碼,這裏是一個門面:

public class ImpersonateServices 
{ 
    public ImpersonateServices(String userName, String domain, String password) 
    { 
     this.UserName = userName; 
     this.Domain = domain; 
     this.Password = password; 
    } 

    public string UserName { get; private set; } 

    public string Domain { get; private set; } 

    public string Password { get; private set; } 

    public void Execute(Action privilegedAction) 
    { 
     CodeImpersonate codeImpersonate = null; 
     try 
     { 
      codeImpersonate = new CodeImpersonate(); 
      var isLoggedIn = codeImpersonate.ImpersonateValidUser(this.UserName, this.Domain, this.Password); 

      if (isLoggedIn){ 
       privilegedAction(); 
      } 
      else 
       throw new InvalidOperationException("Login failed for office user."); 
     } 
     finally 
     { 
      if (codeImpersonate != null) 
       codeImpersonate.UndoImpersonation(); 
      codeImpersonate = null; 
     } 
    } 
} 

使用它像:

var impersonateServices = new ImpersonateServices(AppConfigs.OfficeUser, 
               AppConfigs.OfficeUserDomain, 
               AppConfigs.OfficeUserPass); 
impersonateServices.Execute(() => { 
    //Do your Office work... 
}); 

辦公室 - 用戶應該是有效的本地或域帳戶。 要測試辦公用戶帳戶的工作情況,請使用此用戶帳戶憑證登錄到服務器並啓動MS Word應用程序。如果第一次打開Word,可能會出現一些與彈出窗口相關的設置。解決它們,否則它們可能在編程訪問期間產生問題。

如果您將用戶帳戶憑證保留在配置文件中,請考慮加密值。請參見下面的SO Q &答:

How to encrypt one entry in web.config

Encrypting appSettings in web.config

希望這有助於...

0

下IIS Application PoolsIdentity字段設置爲NetworkService解決了這個問題,在我的設置。