【问题标题】:Office Plugin - Generated Xml Serializer can't find assembly in .NET 4.5Office 插件 - 生成的 Xml 序列化程序在 .NET 4.5 中找不到程序集
【发布时间】:2015-04-18 05:27:38
【问题描述】:

这是一个让我花了一整天时间的问题。我想我会发布解决方案,以防其他人点击它。

我有一个调用 ASMX Web 服务的 .NET Office 插件。它获得了有效的 XML 响应,但 XmlSerializationReader 无法正确反序列化响应。它找不到我的一个 DLL,并引发 FileNotFoundException。

基本结构是这样的:

Utility Assembly -- 包含一些 DTO 所依赖的常用实用程序类。

namespace MyCompany.CommonUtilities
{
    [Serializable]
    public class UtilityClass
    {
        // Various fields and properties..
    }
}

DTO 组装 -- 包含用于 Web 服务调用的可序列化对象

using MyCompany.CommonUtilities;

namespace MyCompany.DtoObjects
{
    [Serializable]
    public class WebResponseDto
    {
        // Various other fields and properties..

        public UtilityClass Property1 { get; set; }
    }
}

这一切都在 .NET 3.5 下运行良好,现在仍然如此。如果我运行针对 3.5 构建的旧插件,一切正常。

发生的事情是,在 .NET 4.5 中,它们完全重新设计了 Xml 序列化程序在运行时生成的方式。请参阅https://stackoverflow.com/a/14699617/3183464 和 .NET 4.5 的自述文件。最终结果是 Xml Serializer 无法为我的 Utilities 项目找到正确的 DLL。

当我编译到 .NET 4.5 时,Web 服务返回一个正确序列化的对象,但它不能在客户端反序列化。相反,我只是得到

Exception: There is an error in XML document (1, 997).

System.IO.FileNotFoundException: Could not load file or assembly 'MyCompany.CommonUtilities, Version=6.0.0.23028, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderMyCompanyService.Read101_WebResponseDto(Boolean isNullable, Boolean checkType)
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderMyCompanyService.Read258_WebMethodResponse()
at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer285.Deserialize(XmlSerializationReader reader)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)

这很令人困惑,因为 Utilities DLL 在调用 Web 服务之前就已经加载了。

查看 Fusion 日志,我看到实用程序程序集的两个不同的加载事件。第一次是我的 Visio 插件第一次加载时,因为它依赖于实用程序类:

LOG: DisplayName = MyCompany.CommonUtilities, Version=6.0.0.23028, Culture=neutral, PublicKeyToken=null (Fully-specified)
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Office/Office14/
Calling assembly : MyCompany.VisioAddIn, Version=6.0.0.23028, Culture=neutral, PublicKeyToken=null.
LOG: This bind starts in LoadFrom load context.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Office/Office14/MyCompany.CommonUtilities.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Office/Office14/MyCompany.CommonUtilities/MyCompany.CommonUtilities.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Office/Office14/MyCompany.CommonUtilities.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Office/Office14/MyCompany.CommonUtilities/MyCompany.CommonUtilities.EXE.
LOG: Attempting download of new URL file:///C:/Users/MyUser/Documents/DevProjects/VisioAddIn/bin/Debug/MyCompany.CommonUtilities.DLL.
LOG: Assembly download was successful. Attempting setup of file: C:\Users\MyUser\Documents\DevProjects\VisioAddIn\bin\Debug\MyCompany.CommonUtilities.dll

注意上下文:它调用Assembly.LoadFrom(),并找到了DLL。

但后来,在运行时生成的序列化程序集尝试加载相同的程序集以反序列化 DTO,但找不到它:

LOG: DisplayName = MyCompany.CommonUtilities, Version=6.0.0.23028, Culture=neutral, PublicKeyToken=null (Fully-specified)
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Office/Office14/
Calling assembly : (Unknown).
LOG: This bind starts in default load context.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Office/Office14/MyCompany.CommonUtilities.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Office/Office14/MyCompany.CommonUtilities/MyCompany.CommonUtilities.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Office/Office14/MyCompany.CommonUtilities.EXE.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Office/Office14/MyCompany.CommonUtilities/MyCompany.CommonUtilities.EXE.
LOG: All probing URLs attempted and failed

看看发生了什么?

运行时生成的程序集没有意识到它需要查看我的插件所在的文件夹。它只是调用Assembly.Load(),它使用默认的加载上下文。

由于它是作为 Visio.EXE 的一部分运行的,Fusion 会搜索明显的位置:C:\Program Files (x86)\Office,但没有找到任何东西。结果:找不到文件。

【问题讨论】:

    标签: c# .net plugins xml-serialization


    【解决方案1】:

    一些没用的东西:

    将 .NET 配置为使用旧的序列化生成。

    <xmlSerializer useLegacySerializerGeneration="true"/>
    

    这似乎没有做任何事情。此外,执行此操作的唯一方法是将 Visio.exe.config 文件添加到 Program Files 文件夹,这具有各种组策略和权限含义。无论如何,它没有工作。

    项目属性 > 构建 > “生成序列化程序集”设置为“开启”

    这生成了一个序列化 DLL,但 Fusion 没有找到该 DLL,就像没有找到实用程序 DLL 一样。 .NET 的序列化引擎没有找到正确的位置。

    什么有效

    将事件处理程序附加到 AppDomain 并在 Assembly.Load() 失败时捕获异常。

    我检查该组件是否属于我的组件。如果是这样,我会查看它是否已经加载——是的,Fusion 可能无法加载已经加载的程序集。如果没有加载,我会在插件的文件夹中查看是否可以找到正确的 DLL。

    结果:一切恢复正常。

    public void PlugInStartup()
    {
        // (other stuff...)
    
        // This allows dynamically-generated DLLs (Xml serializers) to find our DLLs.
        // Because they're not in C:\Program Files\Office, they often can't be found.
    
        AppDomain.CurrentDomain.AssemblyResolve += FindUnresolvedAssembly;
    }
    
    private Assembly FindUnresolvedAssembly(object sender, ResolveEventArgs args)
    {
        string fileName = args.Name.Split(',')[0] + ".dll";
    
        if (!fileName.Contains("MyCompany"))
            // Not our problem
            return null;
    
        Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
    
        Assembly alreadyLoadedAssembly = loadedAssemblies
            .FirstOrDefault(a => a.FullName == args.Name);
    
        if (alreadyLoadedAssembly != null)
            return alreadyLoadedAssembly;
    
        try
        {
            string 
                pluginDir = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
                assemblyPath = System.IO.Path.Combine(pluginDir, fileName);
    
            if (File.Exists(assemblyPath))
                return Assembly.LoadFrom(assemblyPath);
        }
        catch
        { }
    
        return null;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-13
      • 2011-11-12
      • 1970-01-01
      • 2015-02-08
      • 1970-01-01
      相关资源
      最近更新 更多