Alois Kraus

blog

  Home  |   Contact  |   Syndication    |   Login
  109 Posts | 8 Stories | 296 Comments | 162 Trackbacks

News



Article Categories

Archives

Post Categories

Image Galleries

Programming

If you have ever wondered why your .net application has a slow startup performance you normally start watching with Process Explorer at your processes. But this will not always give you the full picture since it can loose some csc.exe calls because if you have a fast machine it will not get them. A more reliable tool is Procmon where you can look for process starts:

Procmon_SlowApplication

Where do these compiler invocations come from? It turns out that XmlSerializer is to blame which generates a C# file in your TEMP folder, compiles it with the C# compiler csc.exe, loads this assembly into the application and removes all traces from your disc after it has done its work. This operation can cost you 0.3 - 2s of your application startup time so it is most of the time worth investigating. The assembly is needed to generate really fast de/serialization code for the types it must de/serialize. There are ways around this by switching to another serializer like DataContractSerializer from .NET Framework 3.0 or to use sgen to generate this seralization assembly only once and for all so it can be loaded later without the code generation overhead. DataContracts do not suffer from the assembly generation overhead because it does not generate any code at all at the cost of a little slower de/serialization.

Sometimes it can be quite hard to find out why some applications cause csc.exe calls. The first thing to use is the fusion log viewer (fuslogvw.exe) which is part of the .NET Framework SDK and is in your path if you start a Visual Studio 20xx command prompt.

image

Here we see assembly load failures for assemblies which names end with .XmlSerializers which is a good way to identify how many compiler calls where made and from which assemblies the de/serialized types originate from. Most of the time this information is enough but there are times when you want to identify the exact types that caused these calls. E.g. you do not want to generate serialization code for all public types of a rather huge assembly which would bloat the code size of the generated serialization assembly or you wan to embed the serialization code into your own assembly.

Luckily XMLSerializer has some debugging capabilities which can be turned on in your application App.config or machine wide if you really want to be sure that you do not miss anything.

The machine config file is located in your windows directory at

%WINDIR%\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config

Here you only need to add

<system.diagnostics>

<switches>

  <add name="XmlSerialization.Compilation" value="true"/>

</switches>

</system.diagnostics>

This will prevent XmlSerializer to clean the %temp% directory up so you have a chance to look at the generated code. Now go to your %TEMP% directory and search for *.cs files.

The the command

findstr /C:"t == typeof" *.cs

will give you the requested types

kzbrxewx.0.cs:                if (t == typeof(global::SlowApplication.Program)) {

in a very easy way. If you are afraid of an additional assembly to load you can also generate with sgen only for the needed type a code file which you can add to your project to stay lightweight. You only need to decorate your serialized type with

[XmlSerializerAssembly("YouMainModule, Version=..., Culture=...,, PublicKeyToken=....")]

That allows your code to stay slim at the expense that you need to regenerate this thing from time to time to stay in sync with the implementation of your serialized types.

 

If you ever wondered if it is possible to use generics within an XMLSerializer serialized class: No you can´t because the XML array type does not know from which collection class it originated from.  If you try to create your custom collection like this

public class FilterItemList : List<FilterItem>

        {

        }


it will not work. But there is a way around it. You only need to name your collection class of the form ArrayOf<ClassName> : List<ClassName> does work.

public class ArrayOfFilterItem : List<FilterItem>

      {

      }

Now we are back in the game and can use fields, properties with our generic type ArrayOfFilterItem  and XmlSerializer will not complain.

posted on Monday, September 14, 2009 11:13 PM