Serialization Circular exception caused by self-referencing Read-only property
When trying to return an object from a JSON asp.net 3.5SP1 WebService (not WCF, classic asp.net WebService with scriptservice attribute), I have an "A circular reference was detected while serializing an object of type 'Geo.Bound'" err开发者_StackOverflowor, caused by a self-referencing Read-only property :
Simplified Code :
Namespace Geo
<DataContract(Namespace:="Geo", IsReference:=True)> _
Public Class Bound
<DataMember(Name:="sw", IsRequired:=False)> _
Public SouthWestCoord As Double
Public Sub New()
SouthWestCoord = 1.5#
End Sub
<IgnoreDataMember()> _
Public ReadOnly Property Bds() As Bound
Get
Return Me
End Get
End Property
End Class
End Namespace
- I want to keep the Read-Only property because it's used for implementing an interface.
- Adding a "IsReference:=True" attribute to Bound class changes nothing.
- If I use a DataContractJsonSerializer (outside the context of webservice, like this exemple : link text), it works and I have a correct JSON.
- If I remove the "Bds" Read-only property it works !!
I don't understand why ! It's a readonly property, without a DataMember attribute, with a IgnoreDatamember attribute, it's not supposed to be serialized !
How to keep the "Bds" property, and get rid of the circular reference exception ?
Thanks !
Here is example, that works (sorry for C#)
Defined class:
[DataContract(Namespace = "Geo")] public class Bound { [IgnoreDataMember] public Bound { get { return this; } } [DataMember] public string Name { get; set; } }
Created Service Interface (and implementation)
[ServiceContract] public interface IService1 { [OperationContract] [WebInvoke(Method = "GET", ResponseFormat = WebMessageFormat.Json)] Bound DoWork(); } public class Service1 : IService1 { public Bound DoWork() { return new Bound { Name = "Test Name" }; } }
Edited system.serviceModel part of app.config
<behaviors> <endpointBehaviors> <behavior name="endBeh"> <enableWebScript/> </behavior> </endpointBehaviors> </behaviors> <services> <service name="JsonSerializationTest.Service1"> <endpoint address="" binding="webHttpBinding" behaviorConfiguration="endBeh" contract="JsonSerializationTest.IService1" /> <host> <baseAddresses> <add baseAddress="http://localhost:8732/Design_Time_Addresses/JsonSerializationTest/Service1/"/> </baseAddresses> </host> </service> </services>
Started Service Host in Program.cs
using (var sh = new ServiceHost(typeof(Service1))) { sh.Open(); Console.WriteLine("Opened"); Console.ReadLine(); }
Started program, opened browser, typed http://localhost:8732/Design_Time_Addresses/JsonSerializationTest/Service1/DoWork and recieved Json-ed test object:
{"d":{"__type":"Bound:Geo","Name":"Test Name"}}
PS: WebInvokeAttribute is located in System.ServiceModel.Web.dll assembly.
You are getting the circular reference Because it's the class Bound with a reference to a property of type Bound. That means it's an endless supply of Bound objects.
Not sure on why IgnoreDataMember isn't working right. I will give this some more time and update my answer if I have any ideas.
精彩评论