The Microsoft Dynamics CRM Blog
News and views from the Microsoft Dynamics CRM Team

Boost performance with Pre-generated XmlSerializers

Boost performance with Pre-generated XmlSerializers

  • Comments 5

Creating an XmlSerializer has a well-known performance cost since .net will generate a temporary helper assembly which requires a compiler call. Additionally, the assembly cannot be unloaded without unloading the hosting application domain causing high memory usage when several XmlSerializer objects are constructed.

Sometimes this assembly-generating process happens in a more indirect manner like the instantiation of a web service proxy class. For example, calling new CrmService() will require an XmlSerializer for the type CrmService which forces .net to generate code, compile and load the assembly. Fortunately, there are alternatives to improve performance and minimize memory usage when creating XmlSerializer objects or instantiating web service proxy classes:

1. Use the pre-generated serializer for CrmService type

If you use a CrmService instance to interact with the CRM server and your project references Microsoft.Crm.SdkTypeProxy.dll, you can add another reference to Microsoft.Crm.SdkTypeProxy.XmlSerializers.dll (you can copy this assembly from the server’s GAC and is also available in the Microsoft Dynamics CRM server installation CD). Because you can make use of the pre-generated serializer then .net will not have to generate a temporary assembly. I experimented this option and noticed a 4-6 second (50% time) performance gain for the CrmService() constructor.

Some considerations:

The processor architecture and version of the assemblies Microsoft.Crm.SdkTypeProxy.XmlSerializers.dll must match and Microsoft.Crm.SdkTypeProxy.dll must match in order to be able to use the pre-generated serializers.

Note that if your code is deployed to the CRM server, the assembly Microsoft.Crm.SdkTypeProxy.XmlSerializers.dll is already in the GAC so you will automatically get the benefit of pre-generated serializers for the CrmService type.

Notice that unless you deploy the code to the CRM server, this gain doesn’t apply if you have a web service reference to CrmService instead of an assembly reference to Microsoft.Crm.SdkTypeProxy.dll.

You can copy the serializer assembly from the GAC to your local project directory by running:

copy c:\Windows\assembly\GAC_MSIL\Microsoft.Crm.SdkTypeProxy.XmlSerializers\4.0.0.0__31bf3856ad364e35\Microsoft.Crm.Sdk.dll <your directory>

2. Use the simple XmlSerializer constructors

When you create an XmlSerializer be very conscientious about the constructor you use. Only if you use XmlSerializer(Type) and XmlSerializer(Type, String) your serializer assemblies will be reused until the application domain is unloaded. However, they will still be generated the first time they are needed. When using all the other constructors, there will be a new generated assembly loaded each time you instantiate an XmlSerializer causing memory and performance losses. Alternatively you could implement your own cache for storing XmlSerializers.

3. Generate your own serializers

If you have created types that need to be serialized using XmlSerializer then whenever possible you should generate the serializer assemblies for these types at build time using tools such as sgen or xgen. This way you totally avoid .net generating temporary assemblies on the fly.

As an example, if you created MyType in MyAssembly.dll and you know this type will be serialized by an XmlSerializer you should run:

Sgen.exe /t:MyType /a:MyAssembly.dll

This will generate the serializer assembly MyAssembly.XmlSerializers.dll which should be added to the current project or to the GAC.

Useful references

Cheers,

Gonzalo Ruiz

  • You can find a tutorial on how to create the XmlSerializers for the crm web service manually on my blog.

  • I find your tutorial very useful, I was not expecting to see such a huge benefit! (~12 seconds in your case).

    Unfortunatelly you'd have to generate your own CrmService proxy which has the disadvantages you pointed out. If you could use the SdkTypeProxy and SdkTypeProxy.XmlSerializers that are shipped woth the product you'd only have to do step 10.

  • Thanks for the article, very useful, I was also thinking whether we can create a pool of proxy objects so that we can re-use them(like Database Connection pool )... is it considered a best practice ?  

  • I've duplicated your steps and am unable to achieve the startup time you have achieved.

    My first step was to right a small console application with a tweak to the app.config so any temporary generated code is persisted after the application finishes and is placed in a different folder. (see Scott Hanselmans blog about this: http://www.hanselman.com/blog/ChangingWhereXmlSerializerOutputsTemporaryAssemblies.aspx)

    //Using the Web Reference method

    DateTime s1 = DateTime.Now;

    new localhost.CrmService();

    DateTime e1 = DateTime.Now;

    double webReferenceTime = (e1 - s1).TotalSeconds;

    //Using the Pre Compiled method

    DateTime s2 = DateTime.Now;

    new Microsoft.Crm.SdkTypeProxy.CrmService();

    DateTime e2 = DateTime.Now;

    double precompiledTime = (e2 - s2).TotalSeconds;

    Test Run 1

    ------------

    Web Reference (without generating XmlSerializer assemblies) - 9.15 seconds

    Pre Compiled Assembly - 9.65 seconds

    Looking at the directory that contains the temporary assemblies I can see 2 different temporary assemblies one for the web reference and one for the pre-compiled assembly

    Test Run 2

    ------------

    Web Reference (with generating XmlSerializer assemblies) - 4.37 seconds

    Pre Compiled Assembly - 9.52 seconds

    Looking at the directory that contains the temporary assemblies again I only see 1 temporary assembly which judging by the times in Test Run 2 would indicate that the Web Reference is using the pre-generated assembly correctly.

    According your blog post as long as the Microsoft.Crm.SdkTypeProxy.XmlSerializers.dll is in the GAC and you are using the same processor architecture and version than the pre-compiled assembly should see a speed increase because it will use the XmlSerializers.dll. This is clearly not the case if you look at the times it takes to instantiate the first CrmService and the temporary files been generated.

    Why isn't this working for me?

  • The only reason I know for which this would not work is if the assembly Microsoft.Crm.SdkTypeProxy.XmlSerializers.dll was generated against a different version of the assembly Microsoft.Crm.SdkTypeProxy.dll that you are using.

    Microsoft.Crm.SdkTypeProxy.XmlSerializers.dll remembers the exact assembly Id of its parent assembly, a way to find out whether they match is to disassemble both assemblies. If both of these assemblies are taken from the same source then they should come from the same build so the assembly Id should match.

Page 1 of 1 (5 items)
Leave a Comment
  • Please add 4 and 6 and type the answer here:
  • Post