Сериализация Циркулярное исключение, вызванное самоссылающейся собственностью только для чтения - PullRequest
2 голосов
/ 01 декабря 2010

При попытке вернуть объект из JSON asp.net 3.5SP1 WebService (не WCF, классический asp.net WebService с атрибутом scriptservice ), у меня появляется "Обнаружена циклическая ссылкапри сериализации объекта типа 'Geo.Bound' " ошибка, вызванная самоссылающимся свойством только для чтения:

Упрощенный код:

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хотите сохранить свойство «Только для чтения», поскольку оно используется для реализации интерфейса.
  • Добавление атрибута «IsReference: = True» в класс Bound ничего не меняет.
  • Если я использую DataContractJsonSerializer (внев контексте веб-сервиса, как этот пример: текст ссылки ), он работает, и у меня есть правильный JSON.
  • Если я удаляю свойство "Bds" только для чтения, оно работает !!

Не понимаю почему!Это свойство только для чтения, без атрибута DataMember, с атрибутом IgnoreDatamember, его нельзя сериализовать!

Как сохранить свойство "Bds" и избавиться от исключения циклической ссылки?

Спасибо!

Ответы [ 2 ]

1 голос
/ 01 декабря 2010

Вот пример, который работает (извините за C #)

  1. Определенный класс:

    [DataContract(Namespace = "Geo")]
    public class Bound
    {
        [IgnoreDataMember]
        public Bound { get { return this; } }
    
    
       [DataMember]
       public string Name { get; set; }
    }
    
  2. Создан сервисный интерфейс (и реализация)

    [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. Отредактированная часть system.serviceModel в 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. Запущен сервисный хост в Program.cs

    using (var sh = new ServiceHost(typeof(Service1)))
    {
        sh.Open();
        Console.WriteLine("Opened");
        Console.ReadLine();
    }
    

Запустил программу, открыл браузер, набрал http://localhost:8732/Design_Time_Addresses/JsonSerializationTest/Service1/DoWork и получил тестовый объект Json-ed:

{"d":{"__type":"Bound:Geo","Name":"Test Name"}}

PS: WebInvokeAttribute находится в System.ServiceModel.Web.dll сборки.

0 голосов
/ 01 декабря 2010

Вы получаете циклическую ссылку, потому что это класс Bound со ссылкой на свойство типа Bound. Это означает, что это бесконечный запас связанных объектов.

Не уверен, почему IgnoreDataMember работает неправильно. Я дам это еще раз и обновлю свой ответ, если у меня появятся какие-либо идеи.

...