我正在使用Microsoft Dynamics CRM进行一些实验。您通过Web服务与它进行交互,并且我已将Web引用添加到我的项目中。 Web服务接口非常丰富,并且生成的“Reference.cs”和是90k左右。

我在控制台应用程序中使用Web引用。我经常改变一些东西,重新编译并运行。编译速度很快,但新增Web服务引用非常慢,大约需要15-20秒: <代码>     CrmService服务=新的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序列化代码。

完整的修复包括以下步骤:

  1. 使用预先生成的XML序列化程序代码创建程序集(DLL)

  2. 从代理代码中删除对System.Xml.Serialization。*属性的所有引用(即从VimService.cs文件中删除)

  3. 使用XmlSerializerAssemblyAttribute注释主代理类,以将其指向XML序列化程序集的位置。

  4. 跳过步骤2导致 VimService 类的实例化时间仅提高20%。跳过步骤1或3会导致代码错误。通过这三个步骤,实现了98%的改进。

    以下是分步说明:

    在开始之前,请确保您使用的是.NET verison 2.0工具。此解决方案不适用于.NET 1.1版,因为sgen工具和 XmlSerializationAssemblyAttribute 仅在.NET 2.0版中可用

    1. 使用wsdl.exe从WSDL生成VimService.cs文件:

      wsdl.exe vim.wsdl vimService.wsdl

      这将在当前目录

    2. 中输出VimService.cs文件
    3. 将VimService.cs编译到库中

      csc / t:library /out:VimService.dll VimService.cs

    4. 使用sgen工具预生成并编译XML序列化程序:

      sgen / p VimService.dll

      这将在当前目录

    5. 中输出VimService.XmlSerializers.dll
    6. 返回VimService.cs文件并删除所有 System.Xml.Serialization。* 属性。因为代码很大,实现它的最好方法是使用一些正则表达式替换工具。这样做时要小心,因为并非所有属性都出现在一行上。有些内容是方法声明的一部分。

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

      假设您正在编写C#,请对以下字符串执行全局替换:

      <代码> [System.Xml.Serialization.XmlIncludeAttribute

      并将其替换为:

      // [System.Xml.Seri

其他提示

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

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

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

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

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

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

this.Proxy = GlobalProxySelection.GetEmptyWebProxy();

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

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 { 
        

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

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

cd..\..
generateproxy

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

<*>

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

-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}"

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

<*>

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top