0

I try to serialize and deserialize the class License.

The serialization work well but when I try to deserialize the file I get the error message above.

This is the base class:

[Serializable]
public abstract class LicenseBase
{
    /// <summary>
    /// Initializes a new instance of the <see cref="LicenseBase"/> class.
    /// </summary>
    protected LicenseBase()
    {
        ApplicationName = string.Empty;
        UniqueId = string.Empty;
    }
    /// <summary>
    /// Application name this license is used for 
    /// </summary>
    [Browsable(false)]
    public string ApplicationName { get; set; }

    /// <summary>
    /// Unique hardware id this license will work on
    /// </summary>
    [Browsable(false)]
    public string UniqueId { get; set; }
}

And this the derived:

public class License : LicenseBase
{
    [Browsable(false)]
    public bool Test { get; set; }
}

This is the method to serialize the class:

public void WriteLicense<T>(T license) where T : LicenseBase
    {
        if (license is null)
        {
            throw new ArgumentNullException(nameof(license));
        }
        //Serialize license object into XML                    
        XmlDocument licenseObject = new XmlDocument();
        using (StringWriter writer = new StringWriter())
        {
            XmlSerializer serializer = new XmlSerializer(typeof(LicenseBase), new[]
            {
                license.GetType(), typeof(License)
            });
            serializer.Serialize(writer, license);
            licenseObject.LoadXml(writer.ToString());
        }

        //Sign the XML
        SignXml(licenseObject);

        //Convert the signed XML into BASE64 string            
        string writeToFile = Convert.ToBase64String(Encoding.UTF8.GetBytes(licenseObject.OuterXml));

        File.WriteAllText(LICENSE_FILENAME, writeToFile);
    }

This is the code to read the class:

    public T ReadLicense<T>() where T : LicenseBase
    {
        T license;

        if (!File.Exists(LICENSE_FILENAME))
        {
            alarmManager.ReportAlarm(licenseFileMissingAlarm, true, true);
            return null;
        }
        string licenseFileData = File.ReadAllText(LICENSE_FILENAME);

        XmlDocument xmlDoc = new XmlDocument { PreserveWhitespace = true };
        xmlDoc.LoadXml(Encoding.UTF8.GetString(Convert.FromBase64String(licenseFileData)));
        // Verify the signature of the signed XML.            
        if (VerifyXml(xmlDoc, PrivateKey))
        {
            XmlNodeList nodeList = xmlDoc.GetElementsByTagName("Signature");
            if (xmlDoc.DocumentElement != null)
            {
                _ = xmlDoc.DocumentElement.RemoveChild(nodeList[0]);
            }

            string licenseContent = xmlDoc.OuterXml;

            //Deserialize license
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            using (StringReader reader = new StringReader(licenseContent))
            {
                license = (T)serializer.Deserialize(reader);
            }
        }
        else
        {
            license = null;
        }

        return license;
    }

The content of licenseContent is

<?xml version="1.0" encoding="UTF-8"?>
<LicenseBase xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="License">
   <ApplicationName>Test</ApplicationName>
   <UniqueId>c4aed5a8-8d22-47b0-bda4-700ac906bfd5</UniqueId>
   <Test>true</Test>
</LicenseBase>
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
  • I ran your XML through a validator [here](https://www.xmlvalidation.com/index.php?id=1&L=0), and got the message *"Cannot resolve 'License' to a type definition for element 'LicenseBase'."* – Robert Harvey Aug 23 '21 at 15:18
  • 1
    can we see your License class? – Allanckw Aug 23 '21 at 15:32
  • Perhaps you need to use a different constructor for `XmlSerializer`, where you define which node is the root (per this [answer](https://stackoverflow.com/a/12672746/3791245)). Note that here you would use the string "LicenseBase" instead of the string in the linked answer. – Sean Skelly Aug 23 '21 at 15:51
  • The element name is `LicenseBase` and there is an attribute `xsi:type="License"` which means that the XML was created by serializing an object of type `License` with an XML serializer `new XmlSerializer(typeof(LicenseBase))`. You need to do the same thing on deserialization, with `[XmlInclude(typeof(License))]` applied to `LicenseBase`. For why see [c# xml deserialization to object with colon and hyphen in xsi:type value](https://stackoverflow.com/a/48978898/3744182) and [Serialize/Deserialize derived class as base class](https://stackoverflow.com/a/43676099/3744182). – dbc Aug 23 '21 at 16:28
  • In fact this may be a duplicate of those two, agree? If no, could you please [edit] your question to share a [mcve], specifically the actual type you are trying to deserialize that corresponds to the generic parameter `T`? – dbc Aug 23 '21 at 16:30
  • You probably have an attribute above the root class [XmlRoot] with a namespace that is not correct. – jdweng Aug 23 '21 at 16:31
  • I Add additional information – Michael Insberg Aug 25 '21 at 10:14

1 Answers1

0

I solve the problem this was the failure;

   XmlSerializer serializer = new XmlSerializer(typeof(LicenseBase), new[]
        {
            license.GetType(), typeof(License)
        });

And this the solution:

  XmlSerializer serializer = new XmlSerializer(license.GetType(), new[]
            {
                license.GetType()
            });

After this changes everything work fine.

  • You need to statically cache and reuse a serializer constructed with extra known types. If not you will get a severe memory leak as explained in [Memory Leak using StreamReader and XmlSerializer](https://stackoverflow.com/a/23897411/3744182). – dbc Aug 26 '21 at 14:33