c# - 慢 SoapHttpClientProtocol 构造函数

标签 c# .net performance xml-serialization soaphttpclientprotocol

我正在用 Microsoft Dynamics CRM 做一些实验。您通过 Web 服务与它交互,并且我已向我的项目添加了一个 Web 引用。 web服务接口(interface)非常丰富,生成的“Reference.cs”有90k左右。

我在控制台应用程序中使用 Web 引用。我经常改变一些东西,重新编译并运行。编译速度很快,但更新 web 服务引用很慢,需要 15-20 秒: CrmService service = new CrmService(); 分析显示所有时间都花在 SoapHttpClientProtocol 构造函数中。

罪魁祸首显然是 XML 序列化代码(不包括在上面提到的 90k loc 中)是在运行时生成的,然后是 JIT。这发生在构造函数调用期间。在玩耍和尝试时,等待是相当令人沮丧的。

我尝试了 sgen.exe、ngen 和 XGenPlus 的各种组合(这需要几个小时并生成 500MB 的附加代码),但无济于事。我已经考虑过实现一个 Windows 服务,该服务几乎没有准备好在需要时提供的 CrmService 实例,但这似乎过度了。

有任何想法吗?

最佳答案

以下内容来自this VMWare 论坛上的主题:

嗨伙计,

我们发现 sgen.exe 确实有效。只是除了预先生成我们在此线程中遗漏的序列化程序 dll 之外,还有几个额外的步骤。这是详细的说明

问题

从 .NET 使用 VIM 2.0 SDK 需要很长时间来实例化 VimService 类。 (VimService类是运行'wsdl.exe vim.wsdl vimService.wsdl'生成的代理类)

换句话说,以下代码行:

_service = new VimService();

执行可能需要大约 50 秒。

原因

显然,.NET XmlSerializer使用 System.Xml.Serialization.*注释代理类以在运行时生成序列化代码的属性。当代理类很多并且很大时,如 VimService.cs 中的代码,序列化代码的生成可能需要很长时间。

解决方案

这是 Microsoft .NET 序列化程序工作方式的一个已知问题。

以下是 MSDN 提供的有关解决此问题的一些引用资料:

http://msdn2.microsoft.com/en-us/library/bk3w6240.aspx
http://msdn2.microsoft.com/en-us/library/system.xml.serialization.xmlserializerassemblyattribute.aspx

不幸的是,以上引用文献都没有描述该问题的完整解决方案。相反,他们专注于如何预先生成 XML 序列化代码。

完整的修复包括以下步骤:
  • 使用预先生成的 XML 序列化程序代码创建程序集(DLL)
  • 从代理代码(即从 VimService.cs 文件)中删除对 System.Xml.Serialization.* 属性的所有引用
  • 使用 XmlSerializerAssemblyAttribute 注释主代理类以将其指向 XML 序列化程序程序集所在的位置。

  • 跳过第 2 步只会使 VimService 的实例化时间缩短 20%。类(class)。跳过第 1 步或第 3 步会导致代码不正确。通过所有三个步骤,实现了 98% 的改进。

    以下是分步说明:

    在开始之前,请确保您使用的是 .NET verison 2.0 工具。此解决方案不适用于 .NET 1.1 版,因为 sgen 工具和 XmlSerializationAssemblyAttribute仅在 .NET 2.0 版中可用
  • 使用 wsdl.exe 从 WSDL 生成 VimService.cs 文件:
    wsdl.exe vim.wsdl vimService.wsdl
    这将输出当前目录中的 VimService.cs 文件
  • 将 VimService.cs 编译成库
    csc /t:library /out:VimService.dll VimService.cs
  • 使用 sgen 工具预生成和编译 XML 序列化程序:
    sgen /p VimService.dll
    这将输出当前目录
  • 中的 VimService.XmlSerializers.dll
  • 返回 VimService.cs 文件并删除所有 System.Xml.Serialization.*属性。由于代码量很大,最好的方法是使用一些正则表达式替换工具。执行此操作时要小心,因为并非所有属性都单独出现在一行中。有些是作为方法声明的一部分内联的。

    如果你觉得这一步很困难,这里有一个简化的方法:

    假设您正在编写 C#,请对以下字符串进行全局替换:
    [System.Xml.Serialization.XmlIncludeAttribute
    并将其替换为:
    // [System.Xml.Serialization.XmlIncludeAttribute
    这将摆脱 Xml.Serialization通过评论它们是导致放缓的最大罪魁祸首的属性。如果您使用的是其他 .NET 语言,只需根据该语言的语法将替换的字符串修改为前缀注释。这种简化的方法将使您获得最大的加速。删除其余的 Xml.Serialization 属性只能实现额外 0.2 秒的加速。
  • 将以下属性添加到 VimService.cs 中的 VimService 类:
    [System.Xml.Serialization.XmlSerializerAssemblyAttribute(AssemblyName = "VimService.XmlSerializers")]
    你应该得到这样的结果:
    // ... Some code here ... [System.Xml.Serialization.XmlSerializerAssemblyAttribute(AssemblyName = "VimService.XmlSerializers")] public partial class VimService : System.Web.Services.Protocols.SoapHttpClientProtocol { // ... More code here
  • 重新生成 VimSerice.dll 库
    csc /t:library /out:VimService.dll VimService.cs
  • 现在,在您的应用程序中,您可以添加对 VimSerice.dll 库的引用。
  • 运行您的应用程序并验证 VimService 对象实例化时间是否减少。

  • 补充说明

    sgen 工具有点像一个黑匣子,它的行为取决于您在 Machine.config 文件中的内容。例如,默认情况下它应该输出优化的非调试代码,但情况并非总是如此。要了解该工具,请在步骤 3 中使用/k 标志,这将使其保留所有临时生成的文件,包括它生成的源文件和命令行选项文件。

    即使在上述修复之后,第一次实例化 VimService 类所需的时间也不是即时的(1.5 秒)。根据经验观察,剩余时间的大部分似乎是由于处理 SoapDocumentMethodAttribute属性。目前还不清楚如何减少这个时间。预先生成的 XmlSerializer 程序集不考虑与 SOAP 相关的属性,因此这些属性需要保留在代码中。好消息是,只有该应用程序的 VimService 类的第一次实例化需要很长时间。因此,如果额外的 1.5 秒有问题,可以尝试在应用程序开始时对此类进行虚拟实例化,以改善用户登录时间的体验。

    关于c# - 慢 SoapHttpClientProtocol 构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/172095/

    相关文章:

    c# - 洋葱架构中的典型层是什么?

    c# - 如何在两个日期之间循环

    c# - ASP.net C# : How to read 20 to 200 GB file line by line using File. ReadLines(文件名).GetEnumerator()?

    c# - .NET 3.5 没有 enum.tryparse,那么如何安全地将字符串解析为枚举?

    .net - IIS 7 - 通过负载均衡器后面的 IP 地址限制应用程序

    .net - 如何使用基于WiX的安装程序为.NET应用程序创建性能计数器?

    performance - 如何使用 mongostats 诊断 mongodb 内部的性能问题

    java - 为什么我不能从 AsyncTask 加载位图?

    performance - JSR223 后处理器在 jmeter 中解析 json

    c# - 具有单元格边框的 OpenXML SDK