Database-First模式下CableApplication对象XML序列化报错如何解决?
我在Visual Studio的C# Database-First项目中,通过.edmx文件自动生成了如下CableApplication类:
public partial class CableApplication : StateObject { [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] public CableApplication() { this.CableProperties = new HashSet<CableProperty>(); } public int Id { get; set; } public int ProjectId { get; set; } public string Application { get; set; } public byte[] ts { get; set; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] public virtual ICollection<CableProperty> CableProperties { get; set; } public virtual Project Project { get; set; } }
我希望将CableApplication的所有数据导出到XML文件中,编写了如下服务端代码:
public string ExportToXml<T>(T obj) { using (var stringwriter = new System.IO.StringWriter()) { TextWriter writer = new StreamWriter(@"d:\temp\check.xml"); var serializer = new XmlSerializer(typeof(T)); serializer.Serialize(stringwriter, obj); writer.Close(); return stringwriter.ToString(); } }
以及前端调用代码:
private void exporToXMLToolStripMenuItem_Click(object sender, EventArgs e) { using (ICableService client = new CableService()) { var applications = client.GetCableApplications(searchList.ToArray(), null, "").ToList(); // 已成功获取CableApplication列表 var str = client.ExportToXml(applications); } }
但运行时出现如下错误:
Cannot serialize member 'Cable1Layer.Domain.CableApplication.CableProperties' of type 'System.Collections.Generic.ICollection`1[[Cable1Layer.Domain.CableProperty, Cable1Layer.Domain, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]', see inner exception for more details
There was an error reflecting type 'Cable1Layer.Domain.CableApplication'
请问该如何正确序列化这个对象?
1. 替换接口类型为可序列化的具体集合
XmlSerializer不支持直接序列化ICollection<T>这类接口,可通过部分类修改属性类型:
因为EDMX生成的是部分类,你可以在同一命名空间下新建一个部分类文件,重定义CableProperties属性:
public partial class CableApplication { [XmlArrayItem("CableProperty")] public virtual HashSet<CableProperty> CableProperties { get; set; } }
这样既不会破坏EDMX自动生成的代码,又能让XmlSerializer识别具体集合类型。
2. 初始化XmlSerializer时指定已知类型
如果不想修改实体类,可在创建序列化器时显式传入集合的具体类型:
public string ExportToXml<T>(T obj) { // 指定需要序列化的集合具体类型 var knownTypes = new Type[] { typeof(HashSet<CableProperty>) }; var serializer = new XmlSerializer(typeof(T), knownTypes); // 用using包裹StreamWriter避免资源泄漏 using (var stringWriter = new System.IO.StringWriter()) using (var fileWriter = new StreamWriter(@"d:\temp\check.xml")) { serializer.Serialize(stringWriter, obj); var xmlContent = stringWriter.ToString(); fileWriter.Write(xmlContent); return xmlContent; } }
3. 处理潜在的循环引用问题
实体类中的virtual导航属性(Project、CableProperties)可能触发EF延迟加载,导致序列化时出现循环引用,可通过以下方式解决:
- 查询数据时关闭延迟加载:
var applications = client.GetCableApplications(searchList.ToArray(), null, "") .AsNoTracking() .ToList(); - 标记不需要序列化的导航属性:
public partial class CableApplication { [XmlIgnore] public virtual Project Project { get; set; } }
内容的提问来源于stack exchange,提问作者nnmmss

