【问题标题】:how to work with Word Document in the C#如何在 C# 中使用 Word 文档
【发布时间】:2012-04-11 14:25:14
【问题描述】:

我有一个问题,起初似乎是许可。 在本地主机上工作正常,但是当转到服务器时发生错误:

[UnauthorizedAccessException: 检索 COM 类工厂 由于 CLSID {000209FF-0000-0000-C000-000000000046} 的组件失败 到以下错误:80070005。]

我使用 IIS7
我给了iis用户权限但无济于事,然后我在代码中传播了“try catch”,发现错误与它尝试创建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 在服务器的 Bin 文件夹中,有没有人知道会发生什么?

谢谢。

【问题讨论】:

  • 嗯?您的服务器是否安装了 Word?
  • 从客户端检查服务,可能是访问权限问题
  • 您不应将 Office 互操作库用于服务器应用程序。这违反了 Microsoft 的建议,因为可能会出现死锁和其他不愉快的情况,会完全破坏您的应用程序。

标签: c# asp.net-mvc reference ms-word


【解决方案1】:

虽然您不应在服务器上使用 Office 互操作库。 Microsoft 不推荐或不支持这种实现,但如果您请求惩罚以克服您的错误,您需要打开服务器上的 DCOM 配置并将身份设置为运行您的应用程序池的用户并授予他们访问启动和激活权限。同样,您不想在服务器上设置 Office 互操作库。

【讨论】:

    【解决方案2】:

    (虽然不建议在服务器中使用office interop,但有时我们必须...)

    问题与安全性有关。 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...
    });
    

    office-User 应该是有效的本地或域帐户。 要测试 office 用户帐户是否正常工作,请使用此用户帐户凭据登录服务器并启动 MS word 应用程序。如果是第一次打开 Word,可能会出现一些设置相关的弹窗。解决它们,否则它们可能会在编程访问期间产生问题。

    如果您将用户帐户凭据保存在配置文件中,请考虑对这些值进行加密。请参阅以下 SO Q&A:

    How to encrypt one entry in web.config

    Encrypting appSettings in web.config

    希望这会有所帮助...

    【讨论】:

      【解决方案3】:

      在 IIS 中的 Application Pools 下,将 Identity 字段设置为 NetworkService 在我的设置中解决了这个问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-05-09
        • 2017-08-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多