Wednesday, November 11, 2009

Practical tutorial on using Sgen.exe to improve performance of XML serialization startup.

There is an overhead incurred when using serialization in your application, which is caused by generation of a ‘helper’ assembly for each type that is serialized with XmlSerializer (per-process-per-domain). (Btw – this has subtle adverse effect – if you use serialization – your application should have Read/Write permissions to %windir%\temp folder).

This overhead may be avoided by using Sgen.exe tool to pre-generate serialization assemblies.
Basically it should be pretty straightforward, especially if your FooBar.dll assembly for which you pre-generating serialization assembly doesn’t has a lot of references. Unfortunately – if you do have a lot of references – you would have to add them all using /reference:c:\foo1\foo1.dll /reference:c:\foo2\foo2.dll /reference:c:\foo3\foo3.dll ……

Here is a workaround:
To generate serialization assembly manually (could be done as a post-build step):
1) Visual Studio –> Foo.csproj –> Properties –> Build –> Generate Serialization Assembly –> On
You would expect it to work automatically now – but it wouldn’t, or saying it more precisely it would create serialization assembly only if your assembly includes proxy types (e.g. web-services).
Anyway – build your assembly, open MSVC output window and look for sgen.exe line in the end of output.
2) Copy whole sgen.exe line – it would include all the references needed.
3) Remove from it /proxytypes parameter – this will cause sgen.exe to generate serializers for regular types.
4) Add /force parameter to force overwrite of previously created assembly.

Now you almost done except of following caveats:
1) If you have types with the same name in different namespaces you would get error saying something like:
Error: There was an error reflecting type ‘FooNamespace.Foo’ – Types ‘FooNamespace1.Foo’ and ‘FooNamespace2.Foo’ both use the XML type name. Use XML attributes to specify a unique XML name and/or namespace for the type.
To resolve it – differentiate your types by specifying XML namespace:
   1:  using System.Xml.Serialization;


   2:   


   3:  [XmlType(Namespace = "urn:Foo1")]


   4:  [XmlRoot(Namespace = "urn:Foo1")]


   5:  public class Foo{}





2)  If you have properties with readonly or internal properties, or internal types – you would get the following error:


Error … property or indexer cannot be assigned to it is read only.

You may either mark such property with [XmlIgnore] attribute or (for internal) – add following line to AssemblyInfo.cs file:





[assembly: InternalsVisibleTo("<AssemblyName>.XmlSerializers, PublicKeyToken=null")]






You may still add it as part of build process manually modifying MSBUILD script in .csproj file.


Look here or here for details.




Technorati Tags: ,,


No comments: