Вызов WCF завершается неудачно, когда результаты возвращаются из Entity Framework

Я создал простое тестовое решение, используя Entity Framework и WCF. У меня есть только одна функция в контракте на обслуживание, называемая GetAllCustomers() который извлекает клиентов из базы данных и возвращает их клиенту. Клиентское приложение вызывает функцию и записывает имена клиентов в консоль.

Когда я звоню GetAllCustomers() от клиента через прокси я получаю CommunicationException с сообщением,

Произошла ошибка при получении ответа HTTP на http://localhost:8000/Service1 , Это может быть связано с тем, что привязка конечной точки службы не использует протокол HTTP. Это также может быть связано с тем, что сервер прерывает контекст HTTP-запроса (возможно, из-за закрытия службы). Смотрите журналы сервера для более подробной информации.

Внутреннее исключение System.Net.WebException:

Основное соединение было закрыто: при получении произошла непредвиденная ошибка.

Следующий уровень внутреннего исключения System.IO.IOException:

Невозможно прочитать данные из транспортного соединения: существующее соединение было принудительно закрыто удаленным хостом.

И последнее внутреннее исключение System.Net.Sockets.SocketException:

Существующее соединение было принудительно закрыто удаленным хостом

Вот код клиента:

static void Main(string[] args)
{
    Console.WriteLine("Press Enter to begin.");
    Console.ReadLine();

    ServiceReference1.Service1Client MyService = new ServiceReference1.Service1Client();

    CUSTOMER[] cl = MyService.GetAllCustomers();

    foreach (CUSTOMER c in cl)
    {
        Console.WriteLine(c.CUSTFNAME + " " + c.CUSTLNAME);
    }

    Console.WriteLine("Press Enter to exit.");
    Console.ReadLine();
}

Вот код приложения хоста:

static void Main(string[] args)
{
    ServiceHost hostA = null;

    try
    {
        hostA = new ServiceHost(typeof(Service1), new Uri("http://localhost:8000") );
        hostA.AddServiceEndpoint(typeof(IService1), new BasicHttpBinding(), "Service1");

        hostA.Open();

        Console.WriteLine();
        Console.WriteLine("Host started.  Press Enter to terminate host.");
        Console.ReadLine();

    }
    finally
    {
        if (hostA.State == CommunicationState.Faulted)
            hostA.Abort();
        else
            hostA.Close();
    }
}

Вот код сервисной библиотеки для функции:

public HashSet<CUSTOMER> GetAllCustomers()
{
    var db = new TRS11Entities();

    HashSet<CUSTOMER> TheCusts = new HashSet<CUSTOMER>();

    foreach (CUSTOMER c in db.CUSTOMERs)
    {
        TheCusts.Add(c);
    }

    //CUSTOMER TestCust1 = new CUSTOMER();
    //TestCust1.CUSTFNAME = "Joe";
    //TestCust1.CUSTLNAME = "Schmoe";
    //CUSTOMER TestCust2 = new CUSTOMER();
    //TestCust2.CUSTFNAME = "Peter";
    //TestCust2.CUSTLNAME = "Pumpkineater";
    //TheCusts.Add(TestCust1);
    //System.Threading.Thread.Sleep(45000);
    //TheCusts.Add(TestCust2);

    return TheCusts;
}

Как ни странно, если я обойду базу данных, заменив блок foreach закомментированным кодом под ним, он прекрасно работает!

Сначала я подумал, что это может быть проблема истечения времени ожидания, поскольку запрос к базе данных занимает слишком много времени. Тем не менее, мой тестовый код спит 45 секунд, и он все еще возвращает данные клиенту в порядке. Исходный код дает исключение только через 3 секунды.

Кроме того, если я вызываю исходную функцию (с блоком foreach), создавая экземпляр службы WCF напрямую, а не через конечную точку / прокси, она также работает нормально и возвращает всех клиентов в базе данных.

Наконец, я подумал, что это может быть проблема с слишком большим набором возвращаемых данных, поэтому я изменил блок foreach и вставил оператор break после добавления первых 5 клиентов в результаты, и я все еще получил исключение.

Итак, что еще может быть причиной этого?

3 ответа

Решение

Я думаю, что проблема заключалась в том, что тип CUSTOMER из Entity Framework содержал наборы (типы контейнеров) подробных записей (продажи и т. Д.), Что делало данные слишком большими. Я закончил тем, что создал новый тип, у которого его не было, и после этого он работал нормально.

Трудно сказать, в чем может быть проблема. Вы можете включить трассировку и диагностику WCF, которые могут дать вам более подробную информацию.

Чтобы быстро приступить к работе - в вашей веб-конфигурации (или приложении):

1) Добавьте раздел System.Diagnostics в любом месте элемента конфигурации. Вы можете заменить путь, по которому вы хотите хранить файлы.

<system.diagnostics>
    <sources>
      <source name="System.ServiceModel.MessageLogging" switchValue="Warning, ActivityTracing">
        <listeners>
          <add type="System.Diagnostics.DefaultTraceListener" name="Default">
            <filter type="" />
          </add>
          <add name="ServiceModelMessageLoggingListener">
            <filter type="" />
          </add>
        </listeners>
      </source>
      <source name="System.ServiceModel" switchValue="Warning, ActivityTracing" propagateActivity="true">
        <listeners>
          <add type="System.Diagnostics.DefaultTraceListener" name="Default">
            <filter type="" />
          </add>
          <add name="ServiceModelTraceListener">
            <filter type="" />
          </add>
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add initializeData="C:\temp\services_messages.svclog" type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="ServiceModelMessageLoggingListener" traceOutputOptions="LogicalOperationStack, DateTime, Timestamp, ProcessId, ThreadId, Callstack">
        <filter type="" />
      </add>
      <add initializeData="C:\temp\services_tracelog.svclog" type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="ServiceModelTraceListener" traceOutputOptions="LogicalOperationStack, DateTime, Timestamp, ProcessId, ThreadId, Callstack">
        <filter type="" />
      </add>
    </sharedListeners>
  </system.diagnostics>

2) Под system.ServiceModel добавьте следующее:

<diagnostics wmiProviderEnabled="false">
      <messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" />
    </diagnostics>

3) В C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\ запустите SvcTraceViewer.exe. Загрузите трассировку сообщений (services_messages.svclog) и журнал трассировки служб (services_tracelog.svclog). Вы можете перетащить файлы в инструмент или открыть один, а затем добавить другой

4) Ищите красные жирные буквы для проблемы.

Если вы хотите сделать процесс редактирования конфигурации WCF более приятным, вы можете использовать SvcConfigEditor.exe, который находится в той же папке, что и SvcTraceViewer.exe (#3). Просто откройте файл конфигурации, и вы увидите папку "Диагностика", которая позволит вам запускать / останавливать и настраивать диагностику.

Если DataContext.ContextOptions.ProxyCreationEnabled = true изменено на false

DataContext.ContextOptions.ProxyCreationEnabled = true

ИЛИ ЖЕ

вернуть клонированного клиента

открытый класс Customer: ICloneable { Public int Id { get; задавать; }

public object Clone()
 {
     var cloneObject = new Customer();
      cloneObject.Id=this.Id; 
      return cloneObject;
 }

}

public HashSet GetAllCustomers () {var db = new TRS11Entities (); HashSet TheCusts = new HashSet (); foreach (CUSTOMER c в db.CUSTOMERs) {TheCusts.Add (c.Clone ()); }

//CUSTOMER TestCust1 = new CUSTOMER();
//TestCust1.CUSTFNAME = "Joe";
//TestCust1.CUSTLNAME = "Schmoe";
//CUSTOMER TestCust2 = new CUSTOMER();
//TestCust2.CUSTFNAME = "Peter";
//TestCust2.CUSTLNAME = "Pumpkineater";
//TheCusts.Add(TestCust1);
//System.Threading.Thread.Sleep(45000);
//TheCusts.Add(TestCust2);

return TheCusts;

}

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