使用XmlSerializer序列化含PSCredential的C#对象至XML时字段为空的问题
解决PSCredential的XML序列化问题
你遇到的问题本质是XmlSerializer默认不支持序列化PSCredential类型:
PSCredential内部的Password是SecureString,这是一种加密的、不可直接读取的类型,XmlSerializer无法自动处理它的序列化。- 同时
PSCredential本身没有标记[Serializable]属性,也没有公开可被序列化的字段,所以默认序列化只会生成空标签。
要实现PSCredential的XML序列化,不能直接依赖XmlSerializer的默认行为,必须自定义序列化逻辑,以下是具体实现方案:
自定义序列化逻辑(实现IXmlSerializable接口)
通过让你的CustomObject实现IXmlSerializable接口,手动控制PSCredential的序列化和反序列化流程。核心思路是利用PowerShell的ConvertFrom-SecureString和ConvertTo-SecureString命令,把SecureString转换成可序列化的加密字符串,再写入XML;反序列化时再把加密字符串转回SecureString。
示例代码:
using System.Xml; using System.Xml.Serialization; using System.Management.Automation; public class CustomObject : IXmlSerializable { public PSCredential DatabaseCredential { get; set; } public PSCredential LaneCredential { get; set; } public XmlSchema GetSchema() => null; public void ReadXml(XmlReader reader) { reader.ReadStartElement(); // 读取DatabaseCredential reader.ReadStartElement("DatabaseCredential"); var dbUsername = reader.ReadElementContentAsString("Username", ""); var dbEncryptedPwd = reader.ReadElementContentAsString("SecurePassword", ""); DatabaseCredential = new PSCredential(dbUsername, ConvertToSecureString(dbEncryptedPwd)); reader.ReadEndElement(); // 读取LaneCredential reader.ReadStartElement("LaneCredential"); var laneUsername = reader.ReadElementContentAsString("Username", ""); var laneEncryptedPwd = reader.ReadElementContentAsString("SecurePassword", ""); LaneCredential = new PSCredential(laneUsername, ConvertToSecureString(laneEncryptedPwd)); reader.ReadEndElement(); reader.ReadEndElement(); } public void WriteXml(XmlWriter writer) { // 序列化DatabaseCredential writer.WriteStartElement("DatabaseCredential"); writer.WriteElementString("Username", DatabaseCredential.UserName); writer.WriteElementString("SecurePassword", ConvertFromSecureString(DatabaseCredential.Password)); writer.WriteEndElement(); // 序列化LaneCredential writer.WriteStartElement("LaneCredential"); writer.WriteElementString("Username", LaneCredential.UserName); writer.WriteElementString("SecurePassword", ConvertFromSecureString(LaneCredential.Password)); writer.WriteEndElement(); } // 封装PowerShell的SecureString转加密字符串逻辑 private string ConvertFromSecureString(SecureString secureStr) { using var ps = PowerShell.Create(); ps.AddCommand("ConvertFrom-SecureString").AddParameter("SecureString", secureStr); return ps.Invoke<string>().FirstOrDefault(); } // 封装加密字符串转SecureString逻辑 private SecureString ConvertToSecureString(string encryptedStr) { using var ps = PowerShell.Create(); ps.AddCommand("ConvertTo-SecureString").AddParameter("String", encryptedStr); return ps.Invoke<SecureString>().FirstOrDefault(); } }
注意事项
- 安全性:
ConvertFrom-SecureString默认使用当前用户的加密密钥生成字符串,只有同一用户在同一机器上才能解密,避免了明文存储密码的风险。如果需要跨用户/机器使用,可添加-Key参数指定自定义密钥,但密钥必须妥善保管。 - 替代方案:如果你的场景允许,也可以直接使用PowerShell内置的
Export-Clixml和Import-Clixml命令(在C#中通过PowerShell类调用),它们原生支持PSCredential的序列化,无需手动实现逻辑。
内容的提问来源于stack exchange,提问作者Qrm
相关产品推荐
相关产品推荐

