(Though it is not recommended to use office interop in server, but sometimes we have to...)
The issue is related to the security. The user identity for the ASP.NET process has not the access rights to use office app, and the identity should have only the minimal permissions required to run your applications. You can use code impersonation to raise the permissions at runtime, without setting up Impersonation in web.config or using a high privilige account for my ASP.NET user account. I have used it in server and I like this approach.
You can google about it to know more.
Here is the code from 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();
}
}
Copy the above code in a file. Here is a sample use of it:
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;
}
To use the above code in several places, here is a facade:
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;
}
}
}
Using it like:
var impersonateServices = new ImpersonateServices(AppConfigs.OfficeUser,
AppConfigs.OfficeUserDomain,
AppConfigs.OfficeUserPass);
impersonateServices.Execute(() => {
//Do your Office work...
});
The office-User should be a valid local or domain account.
To test the office user account working, login to the server using this user account credential and start the MS word application. If the Word is being opened for the first time, some settings related popup might have appeared. Resolve them otherwise they may create issues during programmatic access.
If you keep the user account credential in config file, please consider to encrypt the values. See the below SO Q&A:
How to encrypt one entry in web.config
Encrypting appSettings in web.config
Hope this helps...