You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET 8升级后CustomXml Part无法通过FeedData更新问题排查

.NET 8升级后Word CustomXml Part更新失效问题

将项目从.NET Framework 4.8升级到.NET 8后,原本更新Word文档CustomXml Part的代码报entries cannot be opened multiple times in update mode错误,调整流的读取方式后,新代码调用FeedData却未生效,返回的仍是旧的CustomXml内容。

旧代码(.NET Framework 4.8下可用)

public byte[] RenewCustomXmlPart(byte[] content, string customXml)
{
    using (m_log.CreateScope())
    {
        MemoryStream mem = CreateMemoryStream(content);

        if (mem == null)
        {
            return null;
        }

        using (WordprocessingDocument mergedDocument = WordprocessingDocument.Open(mem, true))
        {
            foreach (CustomXmlPart item in mergedDocument.MainDocumentPart.CustomXmlParts)
            {
                XDocument doc = XDocument.Load(new XmlTextReader(item.GetStream()));
                if (doc.Document == null)
                {
                    throw new ArgumentNullException(nameof(doc.Document));
                }
                if (doc.Document.Root == null)
                {
                    throw new ArgumentNullException(nameof(doc.Document.Root));
                }
                XNamespace xn = doc.Document.Root.GetDefaultNamespace();

                if (xn.NamespaceName == GlobalDefinitions.CustomXmlBausteinNamespace)
                {
                    byte[] a = Encoding.UTF8.GetBytes(customXml);
                    MemoryStream m = new MemoryStream(a);
                    item.FeedData(m);
                }
            }
            mem.Flush();
            return mem.ToArray();
        }
    }
}

新代码(调整后失效)

public byte[] RenewCustomXmlPart(byte[] content, string customXml)
{
    using (m_log.CreateScope())
    {
        using MemoryStream mem = CreateMemoryStream(content);
        if (mem == null)
        {
            return null;
        }

        using WordprocessingDocument mergedDocument = WordprocessingDocument.Open(mem, true);
        foreach (CustomXmlPart item in mergedDocument.MainDocumentPart.CustomXmlParts)
        {
            using (Stream stream = item.GetStream(FileMode.Open, FileAccess.Read))
            {
                XDocument doc = XDocument.Load(new XmlTextReader(stream));
                if (doc.Document == null)
                {
                    throw new ArgumentNullException(nameof(doc.Document));
                }
                if (doc.Document.Root == null)
                {
                    throw new ArgumentNullException(nameof(doc.Document.Root));
                }

                XNamespace xn = doc.Document.Root.GetDefaultNamespace();
                if (xn.NamespaceName != GlobalDefinitions.CustomXmlBausteinNamespace)
                {
                    continue;
                }
            }

            byte[] newCustomXmlBytes = Encoding.UTF8.GetBytes(customXml);
            using MemoryStream m = new(newCustomXmlBytes);
            item.FeedData(m);
        }

        mem.Flush();
        return mem.ToArray();
    }
}

错误原因分析

  1. 集合枚举与修改冲突:.NET 8版本的OpenXML SDK对集合枚举的校验更严格,直接遍历mergedDocument.MainDocumentPart.CustomXmlParts并在循环内修改元素,会导致枚举器无法同步修改后的内容,最终更新无法写入文档包。
  2. 流操作与文档保存逻辑缺失:原代码未显式调用mergedDocument.Save(),仅依赖mem.Flush()无法确保OpenXML的修改完全写入内存流;同时读取流后未处理流位置,可能导致后续写入操作异常。

修正方案代码

public byte[] RenewCustomXmlPart(byte[] content, string customXml)
{
    using (m_log.CreateScope())
    {
        using MemoryStream mem = CreateMemoryStream(content);
        if (mem == null)
        {
            return null;
        }

        using WordprocessingDocument mergedDocument = WordprocessingDocument.Open(mem, true);
        // 先转换为列表,避免枚举时修改集合的同步问题
        var targetParts = mergedDocument.MainDocumentPart.CustomXmlParts.ToList();
        
        foreach (CustomXmlPart item in targetParts)
        {
            XDocument doc;
            using (Stream stream = item.GetStream())
            {
                doc = XDocument.Load(stream);
                stream.Position = 0; // 重置流位置,避免影响后续操作
            }
            
            if (doc.Document?.Root == null)
            {
                throw new ArgumentNullException(nameof(doc.Document.Root));
            }

            XNamespace xn = doc.Document.Root.GetDefaultNamespace();
            if (xn.NamespaceName != GlobalDefinitions.CustomXmlBausteinNamespace)
            {
                continue;
            }

            byte[] newCustomXmlBytes = Encoding.UTF8.GetBytes(customXml);
            using MemoryStream m = new(newCustomXmlBytes);
            m.Position = 0; // 确保写入流从开头开始
            item.FeedData(m);
        }

        // 显式保存文档修改到内存流
        mergedDocument.Save();
        mem.Position = 0; // 重置内存流位置,确保读取完整内容
        return mem.ToArray();
    }
}

内容的提问来源于stack exchange,提问作者Jannik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 02:10:06