DataContractAttribute.IsReference
IsReference property in data contract
It determines how objects are serialized, by default, IsReference=false
.
Setting IsReference = true
allows the serialization of trees of objects that can reference each other. So with a list of Employees
that each have a property for Manager
(who is also an Employee
), a reference to the Manager
for each Employee
can be held rather than embedding the Manager
within each Employee
node:
IsReference=false
would produce:
<Employee>
<Manager i:nil=“true“ />
<Name>Kenny</Name>
</Employee>
<Employee>
<Manager>
<Manager i:nil=“true“ />
<Name>Kenny</Name>
</Manager>
<Name>Bob</Name>
</Employee>
<Employee>
<Manager>
<Manager i:nil=“true“ />
<Name>Kenny</Name>
</Manager>
<Name>Alice</Name>
</Employee>
Where as IsReference=true
would produce:
<Employee z:Id=“i1“ xmlns:z=“http://schemas.microsoft.com/2003/10/Serialization/“>
<Manager i:nil=“true“ />
<Name>Kenny</Name>
</Employee>
<Employee z:Id=“i2“ xmlns:z=“http://schemas.microsoft.com/2003/10/Serialization/“>
<Manager z:Ref=“i1“ />
<Name>Bob</Name>
</Employee>
<Employee z:Id=“i3“ xmlns:z=“http://schemas.microsoft.com/2003/10/Serialization/“>
<Manager z:Ref=“i1“ />
<Name>Alice</Name>
</Employee>
Snippets taken from this weblog that has a full explanation along with examples of the generated XML with the property applied.
MSDN - IsReference Property provides details as well as Interoperable Object References.
DataContract Serializer and IsReference property
In .net Framework 3.5 SP1, DataContractSerializer supports by-ref object graph serialization by using the standard xsd:ID/xsd:IDREF attributes.
You can set the IsReference=true on your DataContract definition and serializer will generate XML elements with IDs/IDREFs attributes and will link them together rather embedding them inside each other(default behavior).
Also if you examine the XSD generated by WCF as part of the metadata export, it will also contain the standard ID/IDREF xml schema attributes. Because of this, xml can be correctly parsed and understood by any framework in a standard way.
This change will enable serialization of object graphs having circular references (which wasn’t possible previously – at least not without writing custom code) and will also reduce the size of the serialized xml.
Let’s examine this change using the following DataContract definition:
[DataContract]
public class Employee
{
[DataMember]
public string Name { get; set; }
[DataMember]
public Employee Manager { get; set; }
}
[DataContract]
public class Department
{
[DataMember]
public List<Employee> Staff { get; set; }
[DataMember]
public string DeptName { get; set; }
}
Now if we serialize following Department object using DataContractSerializer
var kenny = new Employee() { Name = "Kenny" };
var bob = new Employee() { Name = "Bob", Manager = kenny };
var alice = new Employee() { Name = "Alice", Manager = kenny };
var ahmed = new Employee() { Name = "Ahmed", Manager = kenny };
var dept = new Department() { DeptName = "RandD", Staff = new List<Employee>() { kenny, bob, alice, ahmed } };
DataContractSerializer dcs = new DataContractSerializer(typeof(Department));
var ms = new MemoryStream();
dcs.WriteObject(ms, dept);
ms.Seek(0, SeekOrigin.Begin);
var sr = new StreamReader(ms);
var xml = sr.ReadToEnd();
We will get this xml.
<Department xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication2" xmlns:i="http://www.w3.org/2001/XMLSchemainstance">
<DeptName>RandD</DeptName>
<Staff>
<Employee>
<Manager i:nil="true" />
<Name>Kenny</Name>
</Employee>
<Employee>
<Manager>
<Manager i:nil="true" />
<Name>Kenny</Name>
</Manager>
<Name>Bob</Name>
</Employee>
<Employee>
<Manager>
<Manager i:nil="true" />
<Name>Kenny</Name>
</Manager>
<Name>Alice</Name>
</Employee>
<Employee>
<Manager>
<Manager i:nil="true" />
<Name>Kenny</Name>
</Manager>
<Name>Ahmed</Name>
</Employee>
</Staff>
</Department>
You can see manager Kenny is included in all Employee objects, essentially a by-value inclusion. Now if we change the declaration of Employee class to following:
[DataContract(IsReference = true)]
public class Employee
{
[DataMember]
public string Name { get; set; }
[DataMember]
public Employee Manager { get; set; }
}
With above change, you will get following different xml.
<Department xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication2" xmlns:i="http://www.w3.org/2001/XMLSchemainstance">
<DeptName>R&D</DeptName>
<Staff>
<Employee z:Id="i1" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Manager i:nil="true" />
<Name>Kenny</Name>
</Employee>
<Employee z:Id="i2" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Manager z:Ref="i1" />
<Name>Bob</Name>
</Employee>
<Employee z:Id="i3" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Manager z:Ref="i1" />
<Name>Alice</Name>
</Employee>
<Employee z:Id="i4" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<Manager z:Ref="i1" />
<Name>Ahmed</Name>
</Employee>
</Staff>
</Department>
In attribute-free (POCO) world:
you can use a different ctor, taking a boolean flag, to toggle by-val/by-ref serialization.
To enable circular references for operation or service scope, you can use custom behaviors etc. Essentially you need the ability to hook into serializer instantiation process and create the instance using above overload:
1. Subclass DataContractSerializerOperationBehavior
2. Ovverride CreateSerializer method
3. Create a new DCS instance passing true to preserveObjectReferences param.
class DataContractSerializerOperationBehaviorEx : DataContractSerializerOperationBehavior
{
public DataContractSerializerOperationBehaviorEx(OperationDescription operation):base(operation)
{
}
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes, this.MaxItemsInObjectGraph, this.IgnoreExtensionDataObject, true, this.DataContractSurrogate);
}
public override XmlObjectSerializer CreateSerializer(Type type, System.Xml.XmlDictionaryString name, System.Xml.XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, name, ns, knownTypes, this.MaxItemsInObjectGraph, this.IgnoreExtensionDataObject, true, this.DataContractSurrogate);
}
}
作者:Chuck Lu GitHub |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2014-11-20 sqlite的Top筛选