Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.3k views
in Technique[技术] by (71.8m points)

c# - Generating an Xml Serialization assembly for a custom XmlSerializer

I have methods in my class for serializing/deserializing using a different XML structure than what would be produced with the default serializer. The methods create an XmlSerializer for my type but with a whole bunch of overrides. When these methods are called I guess internally .NET still generates a serialization assembly but I would like to generate this assembly after compilation so it's not generated at runtime. How can I generate a serialization assembly for this custom serialization? If I use sgen.exe for that type it appears to only generate the default serializer.

In particular the reason I need to generate the serialization assembly is that my code is called from within Internet Explorer process, which runs in Protected Mode. If the .net runtime tries to generate a serialization assembly it calls csc.exe and the user is prompted, asking whether to allow this process to be run. I don't want users to be prompted! So need all serialization/deserialization to be done without csc.exe.

One option I can think of is capturing that .cs that's generated at runtime, putting it in a separate assembly and then including that in my product. Apart from being a bit icky, that raises the problem of how to auto-generate that .cs as part of my build process ...

Perhaps also worth mentioning: my custom xml serialization also serializes nested classes, so maybe there would be auto-generated serializers for them too. My custom serialization is mostly done along the lines below - it adds XmlIgnore to some properties and removes XmlIgnore from others. Many of these properties return objects that would need to be serialized, some of which implement IXmlSerializable, some use default serialization.

    public void SerializeToCustomXml1(XmlWriter writer)
    {
        try
        {
            CustomXmlSerializer1.Serialize(writer, this);
        }
        catch (Exception)
        {
        }
    }

    /// <summary>
    /// Static serializer so it's created just once. There's another one like this CustomXmlSerializer2 with a slightly different format again.
    /// </summary>
    private static XmlSerializer CustomXmlSerializer1
    {
        get
        {
            if (_customXmlSerializer == null)
            {
                XmlAttributes dontIgnore = new XmlAttributes();
                dontIgnore.XmlIgnore = false;

                XmlAttributes attributes;
                XmlAttributeOverrides overrides = new XmlAttributeOverrides();

                // Include some fields in the XML that wouldn't be there otherwise.
                overrides.Add(typeof (WebResource), "ID", dontIgnore);
                overrides.Add(typeof (WebResource), "HasDestinationURLs", dontIgnore);
                overrides.Add(typeof (Resource), "AccessDefindBy", dontIgnore);

                attributes = new XmlAttributes();
                attributes.XmlIgnore = false;
                attributes.XmlElements.Add(new XmlElementAttribute("ActionID"));
                overrides.Add(typeof(Action), "ID", attributes);

                // Instead of serializing the Actions field we serialize CustomActionsXmlSerializer,
                // which outputs different content in the XML
                overrides.Add(typeof (WebResource), "Actions", ignore);
                attributes = new XmlAttributes();
                attributes.XmlIgnore = false;
                attributes.XmlElements.Add(new XmlElementAttribute("Actions"));
                overrides.Add(typeof (WebResource), "CustomActionsXmlSerializer", attributes);                  

                // ... more of these overrides here ... 
                _customXmlSerializer1 = new XmlSerializer(typeof(WebResource), overrides);
            }
            return _customXmlSerializer1;
        }

Cross-posted here and here.

UPDATE: Oh, this answer suggests it's just not possible as XmlSerializer doesn't even look for a precompiled assembly if you're using XmlOverrides. Darn. Then I guess my best option is to generate the serialization code and include it in my project and call that directly instead of calling XmlSerializer. Any thoughts on how to do this neatly?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you by "custom XmlSerializer" mean that you use System.Xml.XmlSerializer with custom serialization code (either through IXmlSerializable or [XmlElement] attributes and friends), it should be looking for an assembly called MyAssembly.XmlSerializers.dll when serializing.

The naming of the assembly is important, and if you're unsure whether it's being looked for and what exact assembly name is being looked up, you can just attach an event handler to AppDomain.CurrentDomain.FirstChanceException which will fire for all exceptions in the app domain, including assembly loading exceptions. You can also hook into the AppDomain.CurrentDomain.AssemblyLoad and AppDomain.CurrentDomain.AssemblyResolve events, which should fire every time an assembly is first loaded into the app domain.

Another important thing is that the version (and perhaps key; I'm not sure) of MyAssembly.dll and MyAssembly.XmlSerializers.dll must match and they should also be placed alongside each other. See this and this MSDN article for more information.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...