Ms Word插件中的IsolatedStorageException

7
我创建了一个带有功能区的Word插件项目,在使用OpenXml进行几次修改后,当我想要保存文档时,会引发异常。
Dim MainXMLDoc As New XmlDocument()
Using WordDoc As WordprocessingDocument = WordprocessingDocument.Open(DocPath, True)

Dim mainPart As MainDocumentPart = WordDoc.MainDocumentPart
If Not mainPart Is Nothing Then

    MainXMLDoc.Load(mainPart.GetStream())
    EXmlDocument.XMLDoc = Nothing
    EXmlDocument.XMLDoc = MainXMLDoc
    EXmlDocument.GetWordDocIds()
    '..............
end if

'........
Dim stream As IO.Stream
stream = mainPart.GetStream(FileMode.Create, FileAccess.Write)

    MainXMLDoc.Save(stream) '-----> exception

异常信息如下:

Interception de System.IO.IsolatedStorage.IsolatedStorageException  
Message=Unable to determine the identity of domain.   Source=mscorlib 
StackTrace:
       at System.IO.IsolatedStorage.IsolatedStorage._GetAccountingInfo(Evidence
evidence, Type evidenceType, IsolatedStorageScope fAssmDomApp, Object&
oNormalized)
       at System.IO.IsolatedStorage.IsolatedStorage.GetAccountingInfo(Evidence
evidence, Type evidenceType, IsolatedStorageScope fAssmDomApp, String&
typeName, String& instanceName)
       at System.IO.IsolatedStorage.IsolatedStorage._InitStore(IsolatedStorageScope
scope, Evidence domainEv, Type domainEvidenceType, Evidence assemEv,
Type assemblyEvidenceType, Evidence appEv, Type appEvidenceType)
       at System.IO.IsolatedStorage.IsolatedStorage.InitStore(IsolatedStorageScope
scope, Type domainEvidenceType, Type assemblyEvidenceType)
       at System.IO.IsolatedStorage.IsolatedStorageFile.GetStore(IsolatedStorageScope
scope, Type domainEvidenceType, Type assemblyEvidenceType)
       at MS.Internal.IO.Packaging.PackagingUtilities.ReliableIsolatedStorageFileFolder.GetCurrentStore()
       at MS.Internal.IO.Packaging.PackagingUtilities.ReliableIsolatedStorageFileFolder..ctor()
       at MS.Internal.IO.Packaging.PackagingUtilities.GetDefaultIsolatedStorageFile()
       at MS.Internal.IO.Packaging.PackagingUtilities.CreateUserScopedIsolatedStorageFileStreamWithRandomName(Int32
retryCount, String& fileName)
       at MS.Internal.IO.Packaging.SparseMemoryStream.SwitchModeIfNecessary()
       at MS.Internal.IO.Packaging.SparseMemoryStream.Write(Byte[] buffer, Int32 offset, Int32 count)
       at MS.Internal.IO.Packaging.CompressEmulationStream.Write(Byte[] buffer,
Int32 offset, Int32 count)
       at MS.Internal.IO.Packaging.CompressStream.Write(Byte[] buffer, Int32 offset, Int32 count)
       at MS.Internal.IO.Zip.ProgressiveCrcCalculatingStream.Write(Byte[]
buffer, Int32 offset, Int32 count)
       at MS.Internal.IO.Zip.ZipIOModeEnforcingStream.Write(Byte[] buffer, Int32 offset, Int32 count)
       at System.IO.StreamWriter.Flush(Boolean flushStream, Boolean flushEncoder)
       at System.IO.StreamWriter.Write(Char value)
       at System.Xml.XmlTextWriter.Indent(Boolean beforeEndElement)
       at System.Xml.XmlTextWriter.AutoComplete(Token token)
       at System.Xml.XmlTextWriter.WriteStartElement(String prefix, String localName, String ns)
       at System.Xml.XmlDOMTextWriter.WriteStartElement(String prefix, String localName, String ns)
       at System.Xml.XmlElement.WriteStartElement(XmlWriter w)
       at System.Xml.XmlElement.WriteElementTo(XmlWriter writer, XmlElement e)
       at System.Xml.XmlElement.WriteTo(XmlWriter w)
       at System.Xml.XmlDocument.WriteContentTo(XmlWriter xw)
       at System.Xml.XmlDocument.WriteTo(XmlWriter w)
       at System.Xml.XmlDocument.Save(Stream outStream)   InnerException:

当文档大小超过1MB时,会出现这个问题。经过多次搜索,发现“保存”操作是使用独立存储实现的解决方案如下:
  • 使用Clickonce安装
  • 创建新域
  • 修改注册表。
但由于这个项目无法使用ClickOnce并且不能修改注册表,因此我修改了源代码,创建了一个新的域。
Imports DocumentFormat.OpenXml.Packaging
Imports System.IO

<Serializable()> Public Class ToIsolatedPackageSave
    Public Sub Save(ByRef mainPart As MainDocumentPart, ByRef xmlDocument As Xml.XmlDocument)
        Dim stream As IO.Stream
        stream = mainPart.GetStream(FileMode.Create, FileAccess.Write)
        xmlDocument.Save(stream) -----> same exception

    End Sub
End Class

并且
Dim stream As Stream
Dim isolatedPackageSave As ToIsolatedPackageSave
Dim isolatedAppDomain As AppDomain

Try
    Dim isolatedAppDomainSetup As AppDomainSetup = New AppDomainSetup()
    isolatedAppDomainSetup.ApplicationBase = AppDomain.CurrentDomain.BaseDirectory

    Dim isolatedEvidence As Evidence = New Evidence(AppDomain.CurrentDomain.Evidence)
    isolatedEvidence.AddAssembly(Reflection.Assembly.GetExecutingAssembly().FullName)
    isolatedEvidence.AddHost(New Zone(Security.SecurityZone.MyComputer))

    isolatedAppDomain = AppDomain.CreateDomain("TrustIsolatedDomain", isolatedEvidence, isolatedAppDomainSetup)
    isolatedPackageSave = isolatedAppDomain.CreateInstanceAndUnwrap(GetType(ToIsolatedPackageSave).Assembly.FullName, GetType(ToIsolatedPackageSave).FullName)
    '(IsolatedPackageSave)isolatedAppDomainSetup.CreateInstanceAndUnwrap(GetType(ToIsolatedPackageSave).Assembly.FullName, GetType(ToIsolatedPackageSave).FullName)
    isolatedPackageSave.Save(mainPart, MainXMLDoc)
Catch ex As Exception
Finally
    AppDomain.Unload(isolatedAppDomain)
End Try

但是这段代码并没有解决我的问题。
2个回答

13

我在这篇文章中按照Tim Lewis的建议注入所需的安全证据:http://rekiwi.blogspot.com/2008/12/unable-to-determine-identity-of-domain.html

public void VerifySecurityEvidenceForIsolatedStorage(Assembly assembly)
{
    var isEvidenceFound = true;
    var initialAppDomainEvidence = System.Threading.Thread.GetDomain().Evidence;
    try
    {
        // this will fail when the current AppDomain Evidence is instantiated via COM or in PowerShell
        using (var usfdAttempt1 = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForDomain())
        {
        }
    }
    catch (System.IO.IsolatedStorage.IsolatedStorageException e)
    {
        isEvidenceFound = false;
    }

    if (!isEvidenceFound)
    {
        initialAppDomainEvidence.AddHostEvidence(new Url(assembly.Location));
        initialAppDomainEvidence.AddHostEvidence(new Zone(SecurityZone.MyComputer));

        var currentAppDomain = Thread.GetDomain();
        var securityIdentityField = currentAppDomain.GetType().GetField("_SecurityIdentity", BindingFlags.Instance | BindingFlags.NonPublic);
        securityIdentityField.SetValue(currentAppDomain, initialAppDomainEvidence);

        var latestAppDomainEvidence = System.Threading.Thread.GetDomain().Evidence; // setting a breakpoint here will let you inspect the current app domain evidence
    }
}

在启动时调用以下代码:

VerifySecurityEvidenceForIsolatedStorage(this.GetType().Assembly);

2
由于 IsolatedStorageFile 实现了 IDisposable 接口,我建议使用 using (var usfdAttempt1 = IsolatedStorageFile.GetUserStoreForDomain()) {} - Heinzi
我同意你的建议 @Heinzi。我已经更新了上面的代码片段。 - JGeerWM

-1

我认为,在Office插件中无法使用OpenXML。如果您想使用OpenXML,必须在离线状态下进行操作(即文档未打开时)。您只能从插件内部使用COM互操作(Office对象模型调用)。


嗨,Kris,当我们使用OpenXml时,Ms Word仍然处于活动状态,但文档已关闭。 - EurRakanoth
你试过在关闭 MSWord 可执行文件后再尝试吗? - Kris
嗨,Kris, 不行,我不能这样做,因为如果我杀死MsWord,我就会停止进程。该项目是一个Word插件,它在MsWord中运行。 - EurRakanoth

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接