Dynamic Assembly Loading II: SGen and System Defined Classes

Today we’ll look at an example where sgen did not solve the problem with a dynamically loaded XmlSerializers assembly. This issue was found by a customer and filed as a bug on the Microsoft Connect site for SQL Server: https://connect.microsoft.com/SQLServer/feedback/ViewFeedback.aspx?FeedbackID=209210

 

In brief, the code was trying to write out an XmlSchema object to a MemoryStream using XmlTextWriter. Under the covers, however, XmlSchema.Write calls the following:

 

XmlSerializer serializer = new XmlSerializer(typeof(XmlSchema));

This looks just like the typical Xml Serialization use case which sgen was able to solve; however, in this case the clr is looking for an XmlSerializer for the framework defined XmlSchema class, rather than a class that the customer created. Running sgen on the user’s assembly does not create an XmlSerializer for XmlSchema because it is defined in System.Xml.Dll.

 

At first, it seems the workaround to this would be simply to sgen System.Xml.dll for the XmlSchema type and load the resultant XmlSerializers assembly into SQL Server. However, if you try this, you’ll note that running sgen on System.Xml.dll won’t work because System.Xml.dll is signed with Microsoft’s private key, which you are unlikely to have.

 

C:\Windows\Microsoft.NET\Framework\v2.0.50727>sgen /t:System.Xml.Schema.XmlSchema System.Xml.Dll

Microsoft (R) Xml Serialization support utility

[Microsoft (R) .NET Framework, Version 2.0.50727.42]

Copyright (C) Microsoft Corporation. All rights reserved.

Error: Generated serialization assembly is not signed: System.Xml.XmlSerializers, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null. Please specify strong name key file via /compiler:/keyfile:<file> switch.

So what are our other options? One possibility is to incorporate the generated XmlSchema.XmlSerializer dll into the user’s assembly and reference it directly.

After all, what the code is really doing is creating a specialized Serializer for the XmlSchema class. If the XmlSerializer already exists, then we can use it directly and bypass the magic dynamic assembly generation step altogether. Although sgen returned an error because the Serializer assembly isn’t signed and can’t be used automatically, we can instead use the XmlSerializer it generated manually by renaming the file and adding a reference to it in the project.

 

Now all we have to do is change the code to explicitly use our specified XmlSchemaSerializer. In this case, it’s done by replacing the code

 

 GeneratedSchema.Write(Writer)

With

Dim GeneratedSchemaSerializer As XmlSchemaSerializer
GeneratedSchemaSerializer = New XmlSchemaSerializer()
GeneratedSchemaSerializer.Serialize(Writer, GeneratedSchema)

The code now works. Although the workaround is a little messy, it accomplishes the goal of serializing a system defined class without requiring a dynamic assembly to be loaded.