Pregunta

Considera un caso simple

public class Test {
  public String myString;
}

¿Hay alguna forma en que pueda decirle a XmlSerializer que codifique en base64 myString cuando lo serialice?

¿Fue útil?

Solución

Puede simplemente configurarlo para que sea una propiedad de byte [] y Base64 lo codificará automáticamente:

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");

Salida:

<MyProperty>MQAyADMANAA1ADYANwA4ADkAMQAyADMANAA1ADYANwA4ADkA</MyProperty>

(Intente descodificar ese aquí )

Lamentablemente, no hay forma (que yo sepa) de hacer que MyProperty sea privada y aún ser serializada en System.Xml.Serialization .

Otros consejos

Base64 convierte los datos binarios en una cadena. Si desea codificar en base64 los datos en una cadena, primero deberá codificarlos en una matriz de bytes, por ejemplo. utilizando Encoding.UTF.GetBytes (myString) .

Esto plantea la pregunta de por qué exactamente querrías hacer esto en primer lugar. Si necesita usar la base 64, ¿está seguro de que realmente tiene datos de texto para comenzar?

Siguiendo la sugerencia útil de Jon Grant, he implementado un tipo Base64String que encapsula la codificación Base64 requerida.

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
}

Y puedes usar el tipo como este:

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;
}

Almacena la cadena como un valor Base64, y luego tienes una propiedad que la decodifica en la cláusula de obtención.

La única forma compatible de cambiar la salida de la clase XmlSerializer (sin hacks feos como tener propiedades ocultas especiales, etc.) es implementar la interfaz IXmlSerializable .

Podría ahorrar tener que escribir el código de serialización para toda la clase definiendo una clase Base64String que implemente IXmlSerializable y simplemente escriba la cadena codificada. Defina un operador para que sea moldeable implícitamente para una cadena y debería funcionar como lo hace una cadena normal.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top