【问题标题】:XmlSerializer , base64 encode a String memberXmlSerializer , base64 编码一个字符串成员
【发布时间】:2025-12-29 13:45:11
【问题描述】:

考虑一个简单的案例

public class Test {
  public String myString;
}

有什么方法可以告诉 XmlSerializer 在序列化时对 myString 进行 base64 编码?

【问题讨论】:

    标签: c# xml-serialization


    【解决方案1】:

    您可以简单地将其设置为 byte[] 属性,它会自动对其进行 Base64 编码:

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

    输出:

    <MyProperty>MQAyADMANAA1ADYANwA4ADkAMQAyADMANAA1ADYANwA4ADkA</MyProperty>
    

    (尝试解码here

    不幸的是,没有办法(据我所知)将 MyProperty 设为私有并且仍然在 System.Xml.Serialization 中序列化。

    【讨论】:

      【解决方案2】:

      Base64 将 二进制 数据转换为字符串。如果要对字符串中的数据进行 base64 编码,则需要先将其编码为字节数组,例如使用Encoding.UTF.GetBytes(myString)

      这引发了一个问题,即为什么您首先要这样做。如果你需要使用 base 64,你确定你真的有文本数据开始吗?

      【讨论】:

      • 好吧,让字符串文字 " ""\0" 在默认情况下在往返 XML 的往返行程中存活会很好。
      【解决方案3】:

      按照 Jon Grant 的有用建议,我实现了一个 Base64String 类型,它封装了所需的 Base64 编码。

      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
      }
      

      你可以像这样使用类型:

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

      【讨论】:

        【解决方案4】:

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

        【讨论】:

        • +1,尽管我会反其道而行之(存储纯文本,具有仅用于序列化对其进行编码/解码的属性,前提是序列化的使用少于仅访问字符串)。
        【解决方案5】:

        更改XmlSerializer 类的输出的唯一受支持方法(没有丑陋的技巧,例如具有特殊隐藏属性等)是实现IXmlSerializable 接口。

        您可以通过定义一个实现IXmlSerializableBase64String 类并只写出编码字符串来省去为整个类编写序列化代码的麻烦。定义一个操作符,使其 implicitly castable 成为一个字符串,它的工作方式应该和普通字符串一样。

        【讨论】: