我正在使用Microsoft Dynamics CRM进行一些实验.您通过Web服务与它进行交互,并且我已将Web引用添加到我的项目中.Web服务接口非常丰富,生成的"Reference.cs"大约是90k loc.
我在控制台应用程序中使用Web引用.我经常改变一些东西,重新编译并运行.编译速度很快,但是新建Web服务引用非常慢,花费大约15-20秒:
CrmService service = new CrmService();
分析显示所有时间都花在SoapHttpClientProtocol构造函数中.
罪魁祸首显然是XML序列化代码(不包括在上面提到的90k loc中)是在运行时生成,然后才进行JIT.这在构造函数调用期间发生.在玩耍和尝试时,等待是相当令人沮丧的.
我尝试了sgen.exe,ngen和XGenPlus的各种组合(需要几个小时并生成500MB的额外代码),但无济于事.我已经考虑过实现一个几乎没有CrmService实例的Windows服务,可以在需要的时候发布,但这似乎太过分了.
有任何想法吗?
以下内容是从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)
从代理代码中删除对System.Xml.Serialization.*属性的所有引用(即从VimService.cs文件中删除)
使用XmlSerializerAssemblyAttribute注释主代理类,以将其指向XML序列化程序集的位置.
跳过步骤2导致该类的实例化时间仅改善20%VimService
.跳过步骤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秒是一个问题,可以尝试在应用程序开始时对此类进行虚拟实例化,以此作为改善用户登录时间体验的手段.