7

I have a solution with two projects; an asp.net MVC application, and a class library. Let's call them project MVC and project CLS.

In the project CLS, there are two different versions (V1 and V2) of an XSD file that I have used to create two serializable classes with the same name, but under different namespaces (V1 and V2) using xsd2code.

In the MVC project, when the user uploads an XML file, the CLS.dll is used to deserialize the XML into an object. When the XML file is of type V1, the deserialization is very fast, but the XSD file for the V2 version is a lot more complex, and the deserialization can take up to a couple of minutes, only the first time (it's very fast afterwards, until the application is run again).

I used the Sgen.exe tool to create a serializer assembly (CLS.XmlSerializers.dll) for the CLS.V2 type in order to eliminate the first-time creation of the assembly on the fly, and therefore improving the performance.

I have successfully managed to add the Sgen Task to the Post Build events, and the assembly CLS.XmlSerializers.dll is created every time I build the project. Also, I have used the unit test code in this post to make sure the assembly is loaded, and it does. The test passes susscessfully.

However, still, the first time the XML file is deserialized, it takes a long time. So, something still should be wrong. But, I don't know what. Please help.

UPDATE:

I used Fuslogvw.exe as was suggested in the comments, and I can see that the CLS.XmlSerializers.dll is being loaded successfully. Then, how come the first time the XML file is deserialized it takes around one minute, but every time after that takes less than a second?

UPDATE 2:

One of the differences between the two XSD files is that the second one (V2) has a reference to a very big XSD file that containes definitions of some xs:enumeration types that are used in the main file. And, that's the reason the deserialization took a long time. Since all I need to do is to deserialize the XML files into objects and do not need to validate the values of the attributes and elements against those enumerations, I ended up removing the reference to that XSD file, and replacing all the enumeration types with their base types (in this case, xs:string). Now, V2 is deserialized as fast as V1, and I don't even need to use Sgen.exe. I guess Sgen.exe only helps in situations where you need to deserialize a very large XML file. In my case, the XML files are always very small, but the desrialization is (was) complex.

ataravati
  • 8,891
  • 9
  • 57
  • 89
  • "it is slow" is not exactly a guarantee. But sure, always good odds that the DLL is just in the wrong directory. Don't guess at it, run Fuslogvw.exe and log all binds. – Hans Passant Aug 28 '17 at 20:17
  • @HansPassant, see my updated post. – ataravati Aug 28 '17 at 21:06
  • By any chance is your root object some sort of generic collection or container? Those don't always play well with `sgen` assemblies as mentioned [here](https://stackoverflow.com/a/31330743). – dbc Aug 28 '17 at 22:50
  • @dbc, no, it's not. – ataravati Aug 29 '17 at 00:49
  • I'd use procmon and monitor files also. It finds the serializer assembly, but it may take some time to find it. – Simon Mourier Aug 29 '17 at 08:22
  • Check the second update in my question. I ended up doing something different. – ataravati Aug 30 '17 at 14:39
  • I dealt with this a bunch. The serialization assembly created on the fly is your problem. Kudos @eser. The best way is to pre-generate the specific serialization assemblies with `sgen` – Glenn Ferrie Sep 04 '17 at 00:14
  • @GlennFerrie, please read my question carefully. I have used `sgen`. The problem is using `sgen` didn't change anything. – ataravati Sep 04 '17 at 19:21
  • You should run `procmon.exe` to see what's going on. Also, why not do the longer "first run" as part of a warmup script. – Glenn Ferrie Sep 05 '17 at 00:08
  • @GlennFerrie, I would rather avoid doing that. It's not a nice solution. By the way, my issue has been resolved. Please read Update 2 in my question. – ataravati Sep 05 '17 at 15:13
  • @ataravati let me guess, you are dealing with SAT 3.3 changes? Yikes!! I'm dealing with the same stuff too!. Do you have your xds's without the enumeration's by any chance? :D – Hector Sanchez Dec 11 '17 at 22:39
  • @Mr., hahaha! Yes, exactly! And, yes, what I ended up doing was to replace all the enumerations with strings. – ataravati Dec 11 '17 at 22:51
  • @Mr., in my case I only needed to deserialize the XML files into objects. If you need to also serialize objects into XML files, I would recommend loading the enumerations into database tables and do the validations in code. – ataravati Dec 11 '17 at 23:02
  • @ataravati thank you ! :) and good luck for the release at the end of the year! xD Pretty sure is going to be a nightmare xD – Hector Sanchez Dec 12 '17 at 15:38
  • @Mr., I've already released my changes. In my case, it was an expense reporting application. By the way, is there any way I can send you a personal message here in SO? – ataravati Dec 13 '17 at 16:30
  • @ataravati yu know, I'm not really sure but I see there is a chat.stackoverflow.com, otherwise you can contact me to my email which is in my profile now :D – Hector Sanchez Dec 15 '17 at 16:08

2 Answers2

4

In order to increase performance of XML serialization, assemblies are dynamically generated each time XmlSerializer is instantiated for the first time for a specific type. It happens only once in the application lifetime, but that makes its first usage slow.

When you instantiate an XmlSerializer you have to pass the Type of the objects that you will attempt to serialize and deserialize with that serializer instance. The serializer examines all public fields and properties of the Type to learn about which types an instance references at runtime. It then proceeds to create C# code for a set of classes to handle serialization and deserialization using the classes in the System.CodeDOM namespace. During this process, the XmlSerializer checks the reflected type for XML serialization attributes to customize the created classes to the XML format definition. These classes are then compiled into a temporary assembly and called by the Serialize() and Deserialize() methods to perform the XML to object conversions.

Full Content: Troubleshooting Common Problems with the XmlSerializer

More Info: XmlSerializer Constructor Performance Issues

Eser
  • 12,346
  • 1
  • 22
  • 32
  • Please read my question carefully. I have used `sgen` to pre-compile those assemblies that are created the first time. The problem is even using `sgen` didn't make any difference. – ataravati Sep 04 '17 at 19:23
1

It is a known issue of x64 jit compiler, it can be very slow in some cases. That's why you have much better performance when running the deserializtion the second time when code is already compiled.

Try to use .net 4.6 or higher, it features a new version of x64 jit compiler (RyuJIT). If it is not possible to update .net version then take a look at this thread.

Alexander Mokin
  • 2,264
  • 1
  • 9
  • 14
  • I had seen that post before; but isn't Sgen.exe supposed to pre-compile the serializer assembly so it doesn't have to get compiled on the fly? – ataravati Aug 29 '17 at 00:48
  • sgen creates temporary assembly ahead of time, but it still have to be compiled with jit compiler in runtime. To avoid this you have to compile it with ngen. Have you tried upgrading .net or this is not an option? – Alexander Mokin Aug 29 '17 at 08:05
  • I'll try it today, and let you know. – ataravati Aug 29 '17 at 13:59
  • OK, so I did use.net 4.6.1, but it didn't change anything. Also, when I try to install the assembly with `ngen.exe`, it gives me an error saying "The remote procedure call failed." – ataravati Aug 29 '17 at 17:37
  • Weird, when i updated to 4.6.1 from 4.5 i got >20x faster first run. Is there more to this error? Did you try to run ngen on the project.dll or cls.xmlserializers.dll? Also have you considered using different serializer? – Alexander Mokin Aug 29 '17 at 20:25
  • Check the second update in my question. I ended up doing something different. – ataravati Aug 30 '17 at 14:39