【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
当在复杂的环境中面临问题,格物之道需:浊而静之徐清,安以动之徐生。 云中,恰是如此!