我正在用 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 序列化代码。
完整的修复包括以下步骤:
跳过第 2 步只会使
VimService
的实例化时间缩短 20%。类(class)。跳过第 1 步或第 3 步会导致代码不正确。通过所有三个步骤,实现了 98% 的改进。以下是分步说明:
在开始之前,请确保您使用的是 .NET verison 2.0 工具。此解决方案不适用于 .NET 1.1 版,因为 sgen 工具和
XmlSerializationAssemblyAttribute
仅在 .NET 2.0 版中可用wsdl.exe vim.wsdl vimService.wsdl
这将输出当前目录中的 VimService.cs 文件
csc /t:library /out:VimService.dll VimService.cs
sgen /p VimService.dll
这将输出当前目录
System.Xml.Serialization.*
属性。由于代码量很大,最好的方法是使用一些正则表达式替换工具。执行此操作时要小心,因为并非所有属性都单独出现在一行中。有些是作为方法声明的一部分内联的。如果你觉得这一步很困难,这里有一个简化的方法:
假设您正在编写 C#,请对以下字符串进行全局替换:
[System.Xml.Serialization.XmlIncludeAttribute
并将其替换为:
// [System.Xml.Serialization.XmlIncludeAttribute
这将摆脱
Xml.Serialization
通过评论它们是导致放缓的最大罪魁祸首的属性。如果您使用的是其他 .NET 语言,只需根据该语言的语法将替换的字符串修改为前缀注释。这种简化的方法将使您获得最大的加速。删除其余的 Xml.Serialization 属性只能实现额外 0.2 秒的加速。 [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
csc /t:library /out:VimService.dll VimService.cs
补充说明
sgen 工具有点像一个黑匣子,它的行为取决于您在 Machine.config 文件中的内容。例如,默认情况下它应该输出优化的非调试代码,但情况并非总是如此。要了解该工具,请在步骤 3 中使用/k 标志,这将使其保留所有临时生成的文件,包括它生成的源文件和命令行选项文件。
即使在上述修复之后,第一次实例化 VimService 类所需的时间也不是即时的(1.5 秒)。根据经验观察,剩余时间的大部分似乎是由于处理
SoapDocumentMethodAttribute
属性。目前还不清楚如何减少这个时间。预先生成的 XmlSerializer 程序集不考虑与 SOAP 相关的属性,因此这些属性需要保留在代码中。好消息是,只有该应用程序的 VimService 类的第一次实例化需要很长时间。因此,如果额外的 1.5 秒有问题,可以尝试在应用程序开始时对此类进行虚拟实例化,以改善用户登录时间的体验。
关于c# - 慢 SoapHttpClientProtocol 构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/172095/