1

We have an ASP.Net Web application (C#) which is opening a Word file via Microsoft.Office.Interop.Word.

Firstly I realise this is not the recommended approach and a library such as TextControl or Asppose should be considered and we'll be looking at replacing the use of Microsoft.Office.Interop.Word with one such library.

However, in the short term, I would like to get it working and the code we have is working on my development machine, the client's Test server but not their UAT server.

The client's Test server and UAT server are seemingly identical, and I've tried looking at various DCOM Config settings without joy.

I've looked at other Stack Overflow questions on Microsoft.Office.Interop.Word but none of the suggestions have helped.

To help test the issue I put together a simple test application which attempts to open a Word document using the below code

var wordApplication = new Application();            
var wordDocument = wordApplication.Documents.Open(txtPath.Text);
wordApplication.Visible = true;

When run a Word process appears in Task Manager however the below error appears. I've obviously checked file permissions etc. Any suggestions welcome.

enter image description here

DotNetDublin
  • 530
  • 1
  • 5
  • 15
  • 1
    Suppose file exists (test that), it looks like a permission error, "trying to open the file". You host your MVC somewhere. Are you sure that IIS user has permissions to open the document, or access the directory ? – Goodies Jan 29 '21 at 13:15
  • You may consider using NuGet package DocumentFormat.OpenXml https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml?view=openxml-2.8.1. – user9938 Jan 29 '21 at 14:09
  • Have you tried using Server.MapPath: https://docs.microsoft.com/en-us/dotnet/api/system.web.httpserverutility.mappath?view=netframework-4.8. This post may also be useful: https://stackoverflow.com/questions/275781/server-mappath-server-mappath-server-mappath-server-mappath – user9938 Jan 29 '21 at 14:10
  • @Goodies It's definitely reaching the file as if I pass in a path that doesn't exist a different error message is received. I also added "Everyone" permissions on the file to double-check it's not permissions. – DotNetDublin Jan 29 '21 at 15:03
  • @user9938 - Thanks will check out DocumentFormat.OpenXml. Unfortunately the use of Microsoft.Office.Interop.Word is widespread in this application so swapping out won't be a trivial task even if it is the best approach long term. – DotNetDublin Jan 29 '21 at 15:04
  • @user9938 - Using Server.MapPath made no difference. – DotNetDublin Jan 29 '21 at 15:05

2 Answers2

2

The following demo project shows how to upload a Word document file to a web server and then use Microsoft.Office.Interop.Word to read the file.

Pre-requisites:

  • MS Word installed on Web Server computer. (Open Word to ensure that no MessageBox appears--such as "Microsoft Word isn't your default program for viewing and editing documents...")
  • Website contains a folder named: Uploads

Create an ASP .NET Web Application

VS 2017:

  • Open Visual Studio
  • Expand Installed
  • Expand Visual C#
  • Click Web
  • Select ASP.NET Web Application (.NET Framework)
  • Click OK
  • Select Empty
  • Click OK

VS 2019:

  • Open Visual Studio
  • Click Continue without code
  • Click File
  • Select New
  • Select Project
  • C# Windows Web
  • Click ASP .NET Web Application (.NET Framework)
  • Click Next
  • Specify project name (name: AspNetWebApp2)
  • Click Create
  • Click Empty
  • Uncheck Configure for HTTPS
  • Click Create

Note: From this point forward, the process is the same for both VS 2017 and VS 2019.

Add WebForm:

  • In VS menu, click Project
  • Select Add New Item
  • Select Web Form (name: default.aspx)
  • Click Add

Open Solution Explorer

  • In VS menu, click View
  • Select Solution Explorer

In Solution Explorer, double-click "default3.aspx". Replace the code with the following:

default3.aspx

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default3.aspx.cs" Inherits="AspNetWebApp2.Default3" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <div>
         <h3> File Upload:</h3>
         <br />
         <asp:FileUpload ID="FileUpload1" runat="server" />
         <br /><br />
         <asp:Button ID="btnsave" runat="server" onclick="btnsave_Click"  Text="Save" style="width:85px" />
         <br /><br />
         <asp:Label ID="lblmessage" runat="server" />
      </div>

        <div>
            <h2>Data:</h2>
            <div>
                <asp:TextBox ID="textBoxData" runat="server" Height="336px" TextMode="MultiLine" Width="603px"></asp:TextBox>
            </div>
        </div>
    </form>
</body>
</html>

Add a reference (Microsoft Word xx.0 Object Library)

  • In VS menu, click Project
  • Select Add Reference
  • Expand COM
  • Check Microsoft Word xx.0 Object Library (ex: Microsoft Word 16.0 Object Library)

In Solution Explorer, double-click "default3.aspx.cs" and replace the code with the following:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using Word = Microsoft.Office.Interop.Word;

namespace AspNetWebApp2
{
    public partial class Default3 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            
        }

        protected void btnsave_Click(object sender, EventArgs e)
        {
            bool isVisible = true;
            StringBuilder sb = new StringBuilder();
            Word.Application wordApp = null;
            Word.Document doc = null;
            Word.Documents documents = null;

            if (FileUpload1.HasFile)
            {
                try
                {
                    sb.AppendFormat(" Uploading file: {0}", FileUpload1.FileName);

                    //saving the file

                    string localDir = System.IO.Path.Combine(Server.MapPath("."), "Uploads");

                    if (!System.IO.Directory.Exists(localDir))
                    {
                        string errMsg = String.Format("<script>alert('Error - Folder does not exist ({0})');</script>", localDir.Replace(@"\",@"\\"));
                        Response.Write(errMsg);
                    }

                    string localFn = System.IO.Path.Combine(Server.MapPath("."), "Uploads", FileUpload1.FileName);
                    FileUpload1.SaveAs(localFn);

                    //Showing the file information
                    sb.AppendFormat("<br/> Save As: {0}", FileUpload1.PostedFile.FileName);
                    sb.AppendFormat("<br/> File type: {0}", FileUpload1.PostedFile.ContentType);
                    sb.AppendFormat("<br/> File length: {0}", FileUpload1.PostedFile.ContentLength);
                    sb.AppendFormat("<br/> File name: {0}", FileUpload1.PostedFile.FileName);

                    wordApp = new Word.Application();

                    //suppress displaying alerts (such as prompting to overwrite existing file)
                    wordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;

                    //set Word visibility
                    //wordApp.Visible = false;
                    wordApp.Visible = isVisible;

                    if (wordApp != null)
                    {
                        if (File.Exists(localFn))
                        {
                            StringBuilder sbData = new StringBuilder();

                            doc = wordApp.Documents.Open(localFn, System.Reflection.Missing.Value, false, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, isVisible, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value, System.Reflection.Missing.Value);
                            //doc = documents.Open(localFn);

                            doc.Activate();

                            foreach (Word.Paragraph p in doc.Content.Paragraphs)
                            {
                                Debug.WriteLine(p.Range.Text);
                                //Response.Write(p.Range.Text);
                                sbData.AppendLine(p.Range.Text);
                            }

                            textBoxData.Text = sbData.ToString();
                        }
                        else
                        {
                            Debug.WriteLine("Error: Filename '" + localFn + "' doesn't exist.");
                        }
                    }
                }
                catch (Exception ex)
                {
                    sb.Append("<br/> Error <br/>");
                    sb.AppendFormat("Unable to save file <br/> {0}", ex.Message);
                }
                finally
                {
                    if (doc != null)
                    {
                        doc.Close();
                    }

                    if (documents != null)
                    {
                        documents.Close();
                    }

                    if (wordApp != null)
                    {
                        wordApp.Quit();
                        wordApp = null;
                    }
                }
            }
            else
            {
                lblmessage.Text = sb.ToString();
            }

            Debug.WriteLine(sb.ToString());
        }
    }
}

Resources:

user9938
  • 710
  • 4
  • 9
  • You will see that the issue seems to have been down to permissions at the Application Pool/DCOM level however this code is very useful nonetheless. Many thanks. – DotNetDublin Jan 29 '21 at 23:49
2

In the end, my issue was resolved after following the steps outlined on https://stackoverflow.com/a/16481091/1302730.

  • I have created a new user (in user group), called WordUser
  • I have created in IIS new application pool with WordUser permission; Load User Profile must be true
  • DCOM I have set to use WordUser, on Security tab I've added WordUser with Launch and activation Permission and Access Permission

It transpires that it seems the creation of the local user kick-started something as even if I switch the application to use the previous application pool and the DCOM setting to use the previously stipulated user my application works.

DotNetDublin
  • 530
  • 1
  • 5
  • 15