【Azure App Service】使用Microsoft.Office.Interop.Word来操作Word文档,部署到App Service后报错COMException

问题描述

在.NET项目中,使用Microsoft.Office.Interop.Word组件来操作Word文档,使用了Microsoft.Office.Interop.Word.Document对象中的Open和SaveAs方法。

##打开文件

doc = app.Documents.Open(ref inputFile, ref nullobj, ref nullobj, ref nullobj, ref nullobj,ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj,ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj);

##保存文件,关闭文件

doc.SaveAs(ref outputFile, ref nullobj, ref nullobj, ref nullobj, ref nullobj,ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj,ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj);
doc.Close(ref nullobj, ref nullobj, ref nullobj);

但是,在部署到App Service后,遇到 “System.Runtime.InteropServices.COMException (0x80040154): Retrieving the COM class factory for component with CLSID {000209FF-0000-0000-C000-000000000046} failed due to the following error: 80040154 Class not registered (0x80040154 (REGDB_E_CLASSNOTREG)).“ 错误。

完整的错误信息为:

System.Runtime.InteropServices.COMException (0x80040154): Retrieving the COM class factory for component with CLSID {000209FF-0000-0000-C000-000000000046} failed due to the following error: 80040154 Class not registered (0x80040154 (REGDB_E_CLASSNOTREG)).
at Services.Api.Controllers.v1.FileoOerationController.GetFileBasedOnTemplates() in D:\FileOperationController.cs:line 328
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

报错截图:

 

问题解答

Azure App Service 不支持Microsoft.Office.Interop,该扩展需要依赖本地安装的Office, App Service为Sandbox环境,无法安装Office。

替代方案是使用 Open-XML-SDK 来操作 Word 文档。

using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;

OpenAndAddTextToWordDocument(args[0], args[1]);

static void OpenAndAddTextToWordDocument(string filepath, string txt)
{
    // Open a WordprocessingDocument for editing using the filepath.
    WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(filepath, true);

    if (wordprocessingDocument is null)
    {
        throw new ArgumentNullException(nameof(wordprocessingDocument));
    }

    // Assign a reference to the existing document body.
    MainDocumentPart mainDocumentPart = wordprocessingDocument.MainDocumentPart ?? wordprocessingDocument.AddMainDocumentPart();
    mainDocumentPart.Document ??= new Document();
    mainDocumentPart.Document.Body ??= mainDocumentPart.Document.AppendChild(new Body());
    Body body = wordprocessingDocument.MainDocumentPart!.Document!.Body!;

    // Add new text.
    Paragraph para = body.AppendChild(new Paragraph());
    Run run = para.AppendChild(new Run());
    run.AppendChild(new Text(txt));

    // Dispose the handle explicitly.
    wordprocessingDocument.Dispose();
}

(Open and add text to a word processing document : https://learn.microsoft.com/en-us/office/open-xml/word/how-to-open-and-add-text-to-a-word-processing-document?tabs=cs-0%2Ccs-1%2Ccs-2%2Ccs-3%2Ccs

 

附录:使用Microsoft.Office.Interop操作Word的代码

Microsoft.Office.Interop.Word.Application app = new Microsoft.Office.Interop.Word.Application();
Microsoft.Office.Interop.Word.Document doc = null;

string inputFilePath = ".\\testfile1.docx";
string outputFilePath = ".\\testfile1.docx";
object nullobj = Type.Missing;
object inputFile = inputFilePath;
object outputFile = outputFilePath;
object oStory = WdUnits.wdStory;
object oMove = WdMovementType.wdMove;
Dictionary<string, string> datas = new Dictionary<string, string>();
datas["name"] = "namexxxxxxxxx";
datas["code"] = "codexxxxxxxxxx";
app.Visible = false;
app.DisplayAlerts = WdAlertLevel.wdAlertsNone;

doc = app.Documents.Open(ref inputFile, ref nullobj, ref nullobj, ref nullobj, ref nullobj,
    ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj,
    ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj);
object objReplace = Microsoft.Office.Interop.Word.WdReplace.wdReplaceAll;
app.Selection.HomeKey(ref oStory, ref oMove);
app.Options.ReplaceSelection = true;
foreach (var item in datas)
{
    app.Selection.Find.ClearFormatting();
    app.Selection.Find.Replacement.ClearFormatting();
    string oldStr = item.Key;
    string newStr = item.Value;
    if (newStr == null)
    {
        newStr = "";
    }
    app.Selection.Find.Text = oldStr;
    app.Selection.Find.Replacement.Text = newStr;
    app.Selection.Find.Execute(ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj,
        ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj,
        ref objReplace, ref nullobj, ref nullobj, ref nullobj, ref nullobj);
}
doc.SaveAs(ref outputFile, ref nullobj, ref nullobj, ref nullobj, ref nullobj,
    ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj,
    ref nullobj, ref nullobj, ref nullobj, ref nullobj, ref nullobj);
if (doc != null)
{
    doc.Close(ref nullobj, ref nullobj, ref nullobj);
    doc = null;
}
if (app != null)
{
    app.Quit(ref nullobj, ref nullobj, ref nullobj);
    app = null;
}

 

 

参考资料

Can we use Microsoft.Office.Interop.excel.dll in Azure funtions? https://stackoverflow.com/questions/51552404/can-we-use-microsoft-office-interop-excel-dll-in-azure-funtions

App Service Sandbox: https://github.com/projectkudu/kudu/wiki/Azure-Web-App-sandbox

Open and add text to a word processing document : https://learn.microsoft.com/en-us/office/open-xml/word/how-to-open-and-add-text-to-a-word-processing-document?tabs=cs-0%2Ccs-1%2Ccs-2%2Ccs-3%2Ccs 

?? 和 ??= 运算符 - Null 合并操作符: https://learn.microsoft.com/zh-cn/dotnet/csharp/language-reference/operators/null-coalescing-operator

 

posted @ 2024-11-05 20:15  路边两盏灯  阅读(14)  评论(2编辑  收藏  举报