首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> ASP.NET 基礎 >> ASP.NET 基礎

ASP.NET Word 轉 PDF 完整方案:Microsoft Interop 與開源庫雙軌實戰

     編輯:ASP.NET 基礎

方案選型指南

ASP.NET 將 Word 文件(.doc/.docx)轉換為 PDF 主要有三條技術路線:

方案優點缺點適用場景
Microsoft Office Interop零成本、格式還原度最高需伺服器安裝 Office、非執行緒安全、Com 元件權限複雜、效能差內部低併發、格式極度複雜、預算為零
商業庫無 Office 相依、高效能、支援 .NET Core/5+、雲原生授權費用高企業級生產環境、高併發、跨平台
開源庫免費、無 Office 相依、跨平台複雜排版支援有限、維護週期不確定預算受限、簡單文件、.NET Core 專案

一、Microsoft Interop 方案(傳統 ASP.NET Framework 專用)

1.1 先決條件

  1. 伺服器安裝完整版 Microsoft Office(不可僅安裝 Viewer)。
  2. DCOM 設定:dcomcnfg → 元件服務 → Microsoft Word 97-2003 文件 → 身分識別 選「互動使用者」或指定服務帳號。
  3. 專案參考 Microsoft.Office.Interop.Word(NuGet 同名套件)。

1.2 完整轉換元件(含資源釋放保護)

using Microsoft.Office.Interop.Word;
using System;
using System.Runtime.InteropServices;

public static class WordToPdfConverter
{
    public static bool Convert(string sourcePath, string targetPath)
    {
        Application app = null;
        Document doc = null;
        object missing = Type.Missing;

        try
        {
            app = new Application { Visible = false, DisplayAlerts = WdAlertLevel.wdAlertsNone };
            doc = app.Documents.Open(sourcePath, ReadOnly: true, Visible: false);

            doc.ExportAsFixedFormat(
                targetPath,
                WdExportFormat.wdExportFormatPDF,
                OpenAfterExport: false,
                OptimizeFor: WdExportOptimizeFor.wdExportOptimizeForPrint,
                Range: WdExportRange.wdExportAllDocument,
                Item: WdExportItem.wdExportDocumentContent,
                IncludeDocProps: true,
                KeepIRM: true,
                CreateBookmarks: WdExportCreateBookmarks.wdExportCreateWordBookmarks,
                DocStructureTags: true,
                BitmapMissingFonts: true,
                UseISO19005_1: false);

            return true;
        }
        catch (Exception ex)
        {
            // 記錄 Log
            return false;
        }
        finally
        {
            // 嚴格釋放 COM 物件,避免 Word 殭屍進程
            if (doc != null)
            {
                doc.Close(SaveChanges: false);
                Marshal.ReleaseComObject(doc);
            }
            if (app != null)
            {
                app.Quit();
                Marshal.ReleaseComObject(app);
            }
            GC.Collect();
            GC.WaitForPendingFinalizers();
        }
    }
}

1.3 生產環境關鍵優化

  • 物件池化:重用 Application 實例,避免頻繁啟動/關閉 Word 進程(需自行實作執行緒安全池)。
  • 隔離轉換服務:將 Interop 邏輯放入獨立 Windows Service / Console App,透過 Message Queue(RabbitMQ / Azure Queue)非同步處理,Web API 僅負責接收檔案與回傳結果。
  • 監控與自動重啟:偵測 WINWORD.EXE 記憶體超標或掛起時自動回收進程池。

二、跨平台開源方案:FreeSpire.Doc / NPOI / LibreOffice Headless

2.1 FreeSpire.Doc(免費版功能足夠簡單文件)

// NuGet: FreeSpire.Doc
using Spire.Doc;

public static bool ConvertWithFreeSpire(string source, string target)
{
    try
    {
        var doc = new Document();
        doc.LoadFromFile(source);
        doc.SaveToFile(target, FileFormat.PDF);
        return true;
    }
    catch { return false; }
}

2.2 LibreOffice Headless(格式支援最完整的免費方案)

伺服器安裝 LibreOffice,呼叫 CLI:

public static bool ConvertWithLibreOffice(string source, string target)
{
    var psi = new ProcessStartInfo
    {
        FileName = "soffice",
        Arguments = $"--headless --convert-to pdf --outdir \"{Path.GetDirectoryName(target)}\" \"{source}\"",
        UseShellExecute = false,
        CreateNoWindow = true,
        RedirectStandardOutput = true,
        RedirectStandardError = true
    };
    using var proc = Process.Start(psi);
    proc.WaitForExit(120_000); // 2 分鐘超時
    return proc.ExitCode == 0 && File.Exists(target);
}

優點:完美支援複雜排版、跨平台、無授權費。
缺點:啟動較慢、需安裝完整 LibreOffice、非執行緒安全(建議同樣採用訊息佇列隔離)。

三、雲原生最佳實踐架構

// Web API 控制器
[HttpPost("convert")]
public async Task Convert(IFormFile file)
{
    var jobId = Guid.NewGuid();
    var inputPath = $"/storage/input/{jobId}{Path.GetExtension(file.FileName)}";
    var outputPath = $"/storage/output/{jobId}.pdf";

    using (var fs = System.IO.File.Create(inputPath))
        await file.CopyToAsync(fs);

    // 發送轉換任務至佇列
    await _queue.SendMessageAsync(new ConvertJob { JobId = jobId, InputPath = inputPath, OutputPath = outputPath });

    return Accepted(new { JobId = jobId, StatusUrl = Url.Action(nameof(Status), new { jobId }) });
}

// 背景 Worker(獨立進程/容器)
public class ConvertWorker : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        while (!ct.IsCancellationRequested)
        {
            var msg = await _queue.ReceiveMessageAsync(ct);
            if (msg == null) continue;

            var job = JsonSerializer.Deserialize(msg.Body);
            bool success = WordToPdfConverter.Convert(job.InputPath, job.OutputPath); // 或 LibreOffice
            await _resultStore.SetAsync(job.JobId, new { Success = success, FileUrl = success ? $"/download/{job.JobId}.pdf" : null });
            _queue.DeleteMessage(msg);
        }
    }
}

四、常見坑位與解決方案

問題原因解決
8000401A / 80070005 COM 權限錯誤DCOM 身分識別設定錯誤、互動式登入缺失設定 DCOM 為特定服務帳號,並授予「本機啟動/啟動」權限
轉換卡住、Word 進程殭屍未正確釋放 COM 物件、例外導致 Quit 未執行finally 區塊強制 Marshal.ReleaseComObject + GC.Collect;改用隔離服務
字型缺失導致亂碼/版面錯位伺服器缺少文件使用的字型安裝對應字型;或轉換前嵌入字型(Interop 不支援,需商業庫)
.NET Core / Linux 環境無法使用 InteropInterop 僅支援 Windows + Office改用 LibreOffice Headless 或商業跨平台庫

五、總結建議

  1. 新專案優先評估 LibreOffice Headless 或商業庫,避開 Interop 維運地獄。
  2. 現有 Interop 專案務必隔離為獨立服務,Web 層零 COM 相依。
  3. 建立轉換品質自動化測試(像素比對/文字提取驗證),防止升級/字型變更導致回歸。
  4. 監控關鍵指標:轉換成功率、平均耗時、佇列堆積、Word 進程記憶體/數量。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved