Slow SoapHttpClientProtocol构造函数

时间:2008-10-05 14:52:53

标签: c# .net performance xml-serialization soaphttpclientprotocol

我正在使用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服务,可以在需要的时候发布,但这似乎太过分了。

有什么想法吗?

6 个答案:

答案 0 :(得分:36)

答案 1 :(得分:1)

您可能希望查看.NET附带的Sgen.exe工具。在Visual Studio的C#项目属性“Build”页面中,还有一个方便的小东西,在最底层,称为“构建序列化程序集”,它会自动为您运行Sgen

答案 2 :(得分:1)

我认为这不是一个SGEN问题。我已经查看了构造函数代码,我发现它正在进行大量的反射(基于类上的XmlIncludeAttribute)。它反映了所有这些,可能需要很长时间。

答案 3 :(得分:1)

CRM附带了预生成的XmlSerializer程序集。检查GAC中是否有SdkTypeProxy.XmlSerializers.dll和SdkProxy.XmlSerializers.dll。

如果不这样,那意味着当您创建CrmService时,.net将生成XmlSerializer程序集,这可能需要一些时间。 希望这有帮助

答案 4 :(得分:0)

我试图找出为什么我的初始SoapHttpClientProtocol电话花了这么长时间,我遇到了这个帖子。

我发现将Proxy设置为null / Empty会停止Proxy AutoDetect的发生 - 这在初始调用时最多需要7秒钟:

this.Proxy = GlobalProxySelection.GetEmptyWebProxy();

答案 5 :(得分:0)

我已经使用了上面详细的答案作为指导,并向前迈了几步,制作了一个自动化流程的脚本。脚本由两个文件组成:

generateproxy.bat:

REM if your path for wsdl, csc or sgen is missing, please add it here (it varies from machine to machine)
set PATH=%PATH%;C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools;C:\Program Files (x86)\MSBuild\14.0\Bin

wsdl http://localhost:57237/VIM_WS.asmx?wsdl REM create source code out of WSDL
PowerShell.exe -ExecutionPolicy Bypass -Command "& '%~dpn0.ps1'" REM proces source code (remove annotations, add other annotation, put class into namespace)
csc /t:library /out:references\VIM_Service.dll VIM_WS.cs REM compile source into dll
sgen /p references\VIM_Service.dll /force REM generate serializtion dll

generateproxy.ps1

(Get-Content VIM.cs) | 
    ForEach-Object { 
        $_ -replace "(?<attr>\[global::System.Xml.Serialization.[^\]]*\])", "/*${attr}*/" `
            -replace "public partial class VIM", "[System.Xml.Serialization.XmlSerializerAssemblyAttribute(AssemblyName = ""VIM_Service.XmlSerializers"")] `npublic partial class VIM" `
            -replace "using System;", "namespace Classes.WS_VIM {   `n`nusing System;"
    } |
Set-Content VIM.cs
Add-Content VIM.cs "`n}"

我已将这两个文件添加到客户端项目中,并且在预构建事件中我添加了行

cd..\..
generateproxy

因此,在每次构建之前,代理类都会重新生成,而开发人员(几乎)不需要考虑它。构建时,WS必须启动并运行,其URL必须在bat文件中。作为预构建的结果,两个dll文件将在客户端项目的子文件夹引用中重新生成。 首次执行脚本后,您应该添加对新dll的引用。