开发者

Serialization Circular exception caused by self-referencing Read-only property

开发者 https://www.devze.com 2023-01-28 15:10 出处:网络
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 serializin

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#)

  1. Defined class:

    [DataContract(Namespace = "Geo")]
    public class Bound
    {
        [IgnoreDataMember]
        public Bound { get { return this; } }
    
    
       [DataMember]
       public string Name { get; set; }
    }
    
  2. 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" };
        }
    }
    
  3. 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>
    
  4. 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消