WCF: исключение StackoverFlow

Я получаю исключение при попытке обслуживать класс.NET ServiceController. It serializes fine when it's null but once I populate it I get a stackru exception.

Так что это работает:

    [DataMember]
    public ServiceController MyServiceController
    {
        get { return null; }
    }

Но это выдает ошибку "Необработанное исключение типа" System.StackruException "произошло в System.ServiceProcess.dll":

public class TestClass
{
    private ServiceController _serviceController;
    [DataMember]
    public ServiceController MyServiceController
    {
        get { return ServiceController.GetServices()[0];
    }
}

Странно то, что в логах вообще нет ошибок. Когда есть ошибка, я вижу ее в журналах, так что это не потому, что мои журналы не работают. Вот мой конфигурационный файл

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.web>
    <compilation debug="true" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="MyCompany.Wcf.RdbmsServer.RdbmsServiceBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true" httpHelpPageEnabled="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="MyCompany.Wcf.RdbmsServer.RdbmsServiceBehavior"
        name="MyCompany.Wcf.RdbmsServer.RdbmsService">
        <endpoint address="" binding="wsHttpBinding" contract="MyCompany.Wcf.RdbmsServer.IRdbmsService" bindingConfiguration="IncreaseMaxMessageSize">
          <identity>
            <dns value="localhost" />
          </identity>
        </endpoint>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8731/Design_Time_Addresses/MyCompany.Wcf.RdbmsServer/RdbmsService/" />
          </baseAddresses>
        </host>
      </service>
    </services>

    <bindings>
      <wsHttpBinding>
        <binding name="IncreaseMaxMessageSize" 
            maxReceivedMessageSize="655360000">
        </binding>
      </wsHttpBinding>
    </bindings>
  </system.serviceModel>

  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
              switchValue="All"
              propagateActivity="true">
        <listeners>
          <add name="traceListener"
              type="System.Diagnostics.XmlWriterTraceListener"
              initializeData= "c:\Traces.svclog" />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>

</configuration>

Вот мой сервисный интерфейс

[ServiceContract]
public interface IRdbmsService
{
    [OperationContract]
    TestClass GetServiceControllerList();
}

И реализация:

    public TestClass GetServiceControllerList()
    {
       return new TestClass();
    }

Есть идеи?

2 ответа

Решение

Вы вызываете сериализатор для рекурсии:

public class TestClass
{
    private ServiceController _serviceController;
    [DataMember]
    public ServiceController MyServiceController
    {
        get { return ServiceController.GetServices()[0]; // <-- this returns your service
    }
}

Служба, которую он возвращает, является вашей IRdbmsService, который возвращает TestClass, Затем необходимо сериализовать и т. Д.

Изменить: чтобы уточнить:

Когда TestClass сериализуется, сериализатор просматривает все свои DataMember свойства, одним из которых является ServiceController, Затем он сериализует это свойство, которое делает это на get:

return ServiceController.GetServices()[0];

поскольку IRdbmsService является единственной службой, определенной в вашей области, она имеет индекс 0 из ответа GetServices вызов, поэтому он должен быть сериализован. С возвращаемым типом GetServiceControllerList является TestClass, TestClass затем должен быть сериализован, что возвращает нас к началу (отсюда и рекурсия).

То, как решить эту проблему, зависит от того, что вы пытаетесь сделать. В данный момент этот сервис возвращает информацию о себе вызывающей стороне, что для меня не имеет смысла; звонящий уже имеет эту информацию во время потребления (до совершения звонка). Можете ли вы уточнить свои намерения?

Да, в конструкторе ServiceController CLASS вы, вероятно, вызываете что-то рекурсивное, у которого нет условия остановки, поэтому каждый раз, когда оно вызывает что-то рекурсивное, программа переносится в стек, и, как я уже говорил, условия остановки нет, он будет добавляться в стек до тех пор, пока память не взорвется, поэтому ему присваивается имя ошибки StackOverFlow.

Предложение: Добавьте точку останова для отладки там, где ее вызов рекурсивен. Это так легко при отладке.

Другие вопросы по тегам