简体   繁体   中英

XmlSerializer , base64 encode a String member

Consider a simple case

public class Test {
  public String myString;
}

Is there any way I can tell XmlSerializer to base64 encode myString when serializing it ?

Base64 converts binary data into a string. If you want to base64 encode the data in a string, you'd need to encode it in byte array first, eg using Encoding.UTF.GetBytes(myString) .

This raises the question of why exactly you'd want to do this in the first place. If you need to use base 64, are you sure that you've really got text data to start with?

Following Jon Grant useful suggestion I've implemented a Base64String type that encapsulate the required Base64 Encoding.

public class Base64String: IXmlSerializable
{
    private string value;

    public Base64String() { } 

    public Base64String(string value)
    {
        this.value = value;
    }

    public string Value
    {
        get { return value; }
        set { this.value = value; }
    }

    public static implicit operator string(Base64String x)
    {
        return x.ToString();
    }

    public static implicit operator Base64String(string x)
    {
        return new Base64String(x);
    }

    public override string ToString()
    {
        return value;
    }

    #region IXmlSerializable Members

    public System.Xml.Schema.XmlSchema GetSchema()
    {
        return null;
    }

    public void ReadXml(System.Xml.XmlReader reader)
    {
        MemoryStream ms = null;
        byte[] buffer = new byte[256];
        int bytesRead;

        while ((bytesRead = reader.ReadElementContentAsBase64(buffer, 0, buffer.Length)) > 0)
        {
            if (ms == null) 
                ms = new MemoryStream(bytesRead);

            ms.Write(buffer, 0, bytesRead);
        }

        if (ms != null)
            value = System.Text.UnicodeEncoding.Unicode.GetString(ms.ToArray());
    }

    public void WriteXml(System.Xml.XmlWriter writer)
    {
        if (!string.IsNullOrEmpty(value))
        {
            byte[] rawData = Encoding.Unicode.GetBytes(value);
            writer.WriteBase64(rawData, 0, rawData.Length); 
        }
    }

    static public string EncodeTo64(string toEncode)
    {
        byte[] toEncodeAsBytes
              = System.Text.UnicodeEncoding.Unicode.GetBytes(toEncode);
        string returnValue
              = System.Convert.ToBase64String(toEncodeAsBytes);
        return returnValue;
    }

    static public string DecodeFrom64(string encodedData)
    {
        byte[] encodedDataAsBytes
            = System.Convert.FromBase64String(encodedData);
        string returnValue =
           System.Text.UnicodeEncoding.Unicode.GetString(encodedDataAsBytes);
        return returnValue;
    }

    #endregion
}

And you can use the type like this:

static void Main(string[] args)
{
    Foo foo = new Foo();
    foo.Field1 = "Pluto";
    foo.Field2 = "Pippo";
    foo.Field3 = "Topolino";
    foo.Field4 = "Paperino";

    XmlSerializer ser = new XmlSerializer(typeof(Foo));
    ser.Serialize(Console.Out, foo);
    Console.ReadLine();
}

[XmlRoot("Sample")]
public class Foo
{   
    public Foo() { }

    [XmlElement("Alfa_64")]
    public Base64String Field1;

    [XmlElement("Beta")]
    public string Field2;

    [XmlElement("Gamma_64")]
    public Base64String Field3;

    [XmlElement("Delta_64")]
    public Base64String Field4;
}

You can simply set it to be a byte[] property and it will Base64 encode it automatically:

public class Test {
  public byte[] MyProperty {get;set;}

  public void SetMyProperty(string text)
  {
      MyProperty = System.Text.Encoding.Unicode.GetBytes(text);
  }
}

Test test = new Test();
test. SetMyProperty("123456789123456789");

Output:

<MyProperty>MQAyADMANAA1ADYANwA4ADkAMQAyADMANAA1ADYANwA4ADkA</MyProperty>

(Try decoding that here )

Unfortunately there is no way (that I know of) to make MyProperty private and still be serialized in System.Xml.Serialization .

将字符串存储为Base64值,然后具有在get子句中对其进行解码的属性。

The only supported way to change the output from the XmlSerializer class (without ugly hacks like having special hidden properties etc) is to implement the IXmlSerializable interface.

You could save yourself having to write serialization code for the whole class by defining a Base64String class that implements IXmlSerializable and just writes out the encoded string. Define an operator to make it implicitly castable to a string and it should work pretty much like a normal string does.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM