Вызов 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;
}