2010-08-19 13 views
5

Neuling, bitte ertragen mit mir, wie ich gestern mit WCF gerade angefangen habe.WCF mit Entity Framework Fehler Teil II

Ich verwende Northwind für die Daten und fügte nur Kunden, Bestellungen, Bestelldetails und Produkte zum Modell hinzu, also nichts Schickes.

Wenn ich die Anwendung starten und Test aufrufen und einen Haltepunkt festlegen, ist der Wert für Produkte vorhanden und wird ohne Fehler abgeschlossen. Wenn ich dann versuche, GetMaxQuantityByOrderID (10248) aufzurufen, bekomme ich den Fehler unten aufgelistet. Warum würde Test() funktionieren und die gleiche Methode WITHIN Test() funktioniert nicht? Ich fügte sogar einen anderen (Test1(), genau das gleiche wie Test, aber es gibt String zurück: x.ProductName, die korrekt zeigt Queso Cabrales). Es erscheint merkwürdig, dass eine Methode, die innerhalb einer anderen aufgerufen wird, funktioniert, aber sie direkt aufruft, verursacht eine Ausnahme.

Ein anderes Problem, das ich habe, ist, dass das IEnumerable GetOrders() nur funktioniert, wenn ich .ToList() hinzufüge. Ohne es (oder mit. AsEnumerable()), erhalte ich einen Fehler (Die ObjectContext-Instanz wurde entfernt und kann nicht mehr für Operationen verwendet werden, die eine Verbindung erfordern.), obwohl Lazy Loading auf False gesetzt ist. Was ist die Logik dahinter?

IServiceTest.cs

using System.Collections.Generic; 
using System.ServiceModel; 

namespace WcfTestServiceLibrary 
{ 
    [ServiceContract] 
    public interface IServiceTest 
    { 

     [OperationContract] 
     IEnumerable<Orders> GetOrders(); 

     [OperationContract] 
     IEnumerable<Customers> GetCustomers(); 

     [OperationContract] 
     Customers GetCustomerByID(string customerID); 

     [OperationContract] 
     Orders GetOrderByID(int id); 

     [OperationContract] 
     IEnumerable<Order_Details> GetOrderDetailsByOrderID(int id); 

     [OperationContract] 
     Order_Details GetMaxQuantityByOrderID(int id); 

     [OperationContract] 
     void Test(); 
    } 
} 

ServiceTest.cs

using System.Collections.Generic; 
using System.Linq; 

namespace WcfTestServiceLibrary 
{ 

    public class ServiceTest : IServiceTest 
    { 
     public IEnumerable<Orders> GetOrders() 
     { 
      using (var ctx = new NWEntities()) 
      { 
       return (from o in ctx.Orders.Include("Order_Details.Products").Include("Customers") 
         select o).ToList(); 
      } 
     } 

     public IEnumerable<Customers> GetCustomers() 
     { 
      using (var ctx = new NWEntities()) 
      { 
       return (from c in ctx.Customers 
         select c); 
      } 
     } 

     public Customers GetCustomerByID(string customerID) 
     { 
      return (from c in GetCustomers() 
        where c.CustomerID == customerID 
        select c).FirstOrDefault(); 
     } 

     public Orders GetOrderByID(int id) 
     { 
      IEnumerable<Orders> orders = GetOrders(); 
      return (from o in orders 
        where o.OrderID == id 
        select o).FirstOrDefault(); 
     } 

     public IEnumerable<Order_Details> GetOrderDetailsByOrderID(int id) 
     { 
      return GetOrderByID(id).Order_Details; 
     } 

     public Order_Details GetMaxQuantityByOrderID(int id) 
     { 
      Orders order = GetOrderByID(id); 
      return order == null ? null : order.Order_Details.OrderByDescending(x => x.Quantity).FirstOrDefault(); 

     } 

     public void Test() 
     { 
      const int orderID = 10248; 
      var oq = GetMaxQuantityByOrderID(orderID); 
      var x = oq.Products; 
     } 
    } 
} 

Fehler:

An error occurred while receiving the HTTP response to http://localhost:8732/Design_Time_Addresses/WcfTestServiceLibrary/Service1/. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details. 

Server stack trace: 
    at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason) 
    at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout) 
    at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout) 
    at System.ServiceModel.Channels.ClientReliableChannelBinder`1.RequestClientReliableChannelBinder`1.OnRequest(TRequestChannel channel, Message message, TimeSpan timeout, MaskingMode maskingMode) 
    at System.ServiceModel.Channels.ClientReliableChannelBinder`1.Request(Message message, TimeSpan timeout, MaskingMode maskingMode) 
    at System.ServiceModel.Channels.ClientReliableChannelBinder`1.Request(Message message, TimeSpan timeout) 
    at System.ServiceModel.Security.SecuritySessionClientSettings`1.SecurityRequestSessionChannel.Request(Message message, TimeSpan timeout) 
    at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout) 
    at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout) 
    at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation) 
    at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message) 

Exception rethrown at [0]: 
    at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) 
    at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) 
    at IServiceTest.GetMaxQuantityByOrderID(Int32 id) 
    at ServiceTestClient.GetMaxQuantityByOrderID(Int32 id) 

Inner Exception: 
The underlying connection was closed: An unexpected error occurred on a receive. 
    at System.Net.HttpWebRequest.GetResponse() 
    at System.ServiceModel.Channels.HttpChannelFactory.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout) 

Inner Exception: 
Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. 
    at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size) 
    at System.Net.PooledStream.Read(Byte[] buffer, Int32 offset, Int32 size) 
    at System.Net.Connection.SyncRead(HttpWebRequest request, Boolean userRetrievedStream, Boolean probeRead) 

Inner Exception: 
An existing connection was forcibly closed by the remote host 
    at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags) 
    at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size) 

Antwort

1

Für die erste Ausgabe anprobieren WCF tracing auf Ihrem Dienst einzuschalten. Das zweite Problem mit IEnumerable wird durch die Ausführung verursacht. Übrigens. Verstehen Sie den Unterschied zwischen IQueryable <T> und IEnumerable <T>? Wissen Sie, dass Ihre GetOrders-Methode alle Aufträge, zugehörigen Kunden und Produkte in den Speicher lädt? Selbst wenn Sie eine einzelne Bestellung auswählen möchten, laden Sie immer noch alle im Service.

Edit:

WCF Tracing wird Ihnen zeigen, was während der Wartung oder Client-Ausführung passiert - es zeichnet Interna WCF und es ist wichtiges Instrument für die WCF-Entwicklung. Tutorial zur WCF-Ablaufverfolgung und trace viewer.

IQueryable erstellt einen Ausdrucksbaum, der in eine Datenbankabfrage kompiliert wird, sodass Sie diese Abfrage (Ausführung außerhalb des Kontextbereichs) nicht ausführen können (Kontext ist für die Datenbankverbindung verantwortlich). Sie müssen Ihre Methoden neu schreiben. In Ihrem Fall muss jede Methode eine vollständige Abfrage erstellen und diese Abfrage innerhalb des Kontextbereichs ausführen. Die Ausführung der Abfrage erfolgt durch Auswahl eines einzelnen Datensatzes (wie FirstOrDefault()) oder durch Umwandlung in eine Liste.

+0

Wenn ich IQueryable zu ändern, erhalte ich die Fehler Die Object Instanz angeordnet ist und kann nicht mehr für den Betrieb, die eine Verbindung erfordern verwendet werden. Was ist der richtige Weg, WCF-Dienste zu tun? Ich verstehe nicht, was die Konfiguration der Ablaufverfolgung mir erlauben wird. Wie gesagt, ich habe vor 2 Tagen mit WCF angefangen. –

+0

Ich habe einige Informationen über Tracing und EF hinzugefügt. –

+0

Das Problem tritt nur im WCF-Test-Client auf. Wenn ich den Client nicht verwende und eine asp.net-Seite für Ergebnisse verwende, funktioniert es. –

8

Ich hatte ein sehr ähnliches Problem wie Sie. Ich habe herausgefunden, dass der Entity Framework-Proxy, der Ihre POCO-Klassen umschließt, standardmäßig vom WCF-Serializer serialisiert wird, der auf der Clientseite nicht deserialisiert werden kann, da der Client den EF-Proxy-Wrapper nicht kennt. Es gab zwei Lösungen, die ich fand. Die erste besteht darin, ContextOptions.ProxyCreationEnabled auf false zu setzen. Dies verhindert, dass die EF Proxys für Ihre POCO-Objekte erstellt. Die zweite Aufgabe bestand darin, den WCF DataContractSerializer auf der Serverseite anzuweisen, den ProxyDataContractResolver nur als POCO zu serialisieren.

Die zweite Option finden Sie unter http://msdn.microsoft.com/en-us/library/ee705457.aspx. Da ich gerade diese Lösungen entdeckt habe, kann ich nicht sagen, was ich als allgemeine Praxis empfehlen würde, obwohl ich mich auf Letzteres stütze, da die EF-Abfragen von anderen Anrufern von Zeit zu Zeit wiederverwendet werden können, die Objekte zurückgeben möchten mit den entsprechenden EF-Proxies. Jedenfalls weiß ich, dass es zu spät zu dieser Frage kommt, aber ich hoffe, dass dies anderen hilft, die auf dieses Problem stoßen.

+0

Danke, erste Lösung verwenden, hilft sehr – Dzmitry

+0

Danke für die Info, war wirklich hilfreich –

3

Es ist die .Inculde in Ihrer LINQ-Anweisung.

Ich glaube der Grund dafür ist die grundlegende resultierende unendliche Datenstruktur, die auf und von "einer" Seite zu der "vielen" Seite Ihrer Beziehung zeigt.

Dies Sie Ihre Datenstruktur durch Entfalten beobachten können, einen Haltepunkt an dem Ergebnis Ihrer .INCLUDE Abfrageanweisung im Debugger Einstellung ...

Beobachtung: Bestellungen -> viele Produkte, jedes Produkt -> Bestellung -> viele Produkte und so weiter

Ich denke, dass der rfn in das hineinrennt und in diesem gefangen wird.

diese Kette von brechen, können Sie einfach das vermeiden zurück in Ihrem Datentransferobjekt zeigt durch die ignoreDataMember

In der n-Seite Ihrer Beziehung Attribut Hinzufügen ... In Ihrem Fall des Produkt .. ..

[IgnoreDataMember] öffentliche Bestellung OrderFatherElement {erhalten; einstellen; }

Auf diese Weise WCF die serializingattempt zu stoppen, wenn

@microsoft .... einige Potenzial für eine Korrektur, die childNode zu erreichen?

Greets,

Kieredin Garbaa