2010-08-19 17 views
5

Newbie, per favore abbiate pazienza con me come ho appena iniziato ieri con WCF.WCF con errore di Entity Framework Parte II

Sto utilizzando Northwind per i dati e ho aggiunto solo clienti, ordini, dettagli dell'ordine e prodotti al modello, quindi niente di eccezionale.

Quando avvio l'applicazione e invoco Test e imposta un punto di interruzione, il valore per i prodotti è lì e viene completato senza errori. Se poi provo a richiamare GetMaxQuantityByOrderID (10248), viene visualizzato l'errore in basso. Perché Test() funziona e lo stesso metodo WITHIN Test() NON funziona? Ho anche aggiunto un altro (Test1(), esattamente come Test tranne che restituisce stringa: x.ProductName, che visualizza correttamente Queso Cabrales). Sembra strano che un metodo che viene chiamato all'interno di un altro funziona, ma chiamarlo direttamente provoca un'eccezione.

Un altro problema che ho è che IEnumerable GetOrders() funziona solo se aggiungo .ToList(). Senza di esso (o con .AsEnumerable()), viene visualizzato un errore (L'istanza ObjectContext è stata eliminata e non può più essere utilizzata per operazioni che richiedono una connessione.), anche se il caricamento lento è impostato su False. Qual è la logica dietro a questo?

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; 
     } 
    } 
} 

Errore:

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) 

risposta

1

Per il primo numero cercare di trasformare il WCF tracing sul vostro servizio. Il secondo problema con IEnumerable è causato dall'esecuzione defferente. Btw. capisci la differenza tra IQueryable <T> e IEnumerable <T>? Sai che il tuo metodo GetOrders carica tutti gli ordini, i clienti e i prodotti correlati in memoria? Anche se desideri selezionare un singolo ordine, li carichi ancora tutti nel servizio.

Edit:

WCF tracciato vi mostrerà che cosa è accaduto durante il servizio o un client di esecuzione - si ripercorre interni WCF ed è strumento essenziale per lo sviluppo WCF. Esercitazione su tracciamento WCF e trace viewer.

IQueryable genera un albero di espressioni che viene compilato nella query del database in modo che non sia possibile eseguire tale query (esecuzione disattivata) al di fuori del contesto (il contesto è responsabile della connessione al database). Devi riscrivere i tuoi metodi. Nel tuo caso, ogni metodo deve creare una query completa ed eseguire quella query all'interno del contesto. L'esecuzione della query viene eseguita selezionando un singolo record (come FirstOrDefault()) o convertendolo in elenco.

+0

se cambio di IQueryable, ottengo l'errore L'istanza ObjectContext è stato eliminato e non possono più essere utilizzati per operazioni che richiedono una connessione. Qual è il modo corretto di fare servizi WCF? Non capisco cosa mi consenta di configurare la traccia. Come ho detto, ho appena iniziato con WCF 2 giorni fa. –

+0

Ho aggiunto alcune informazioni sulla traccia e EF. –

+0

Il problema si verifica solo nel client di test WCF. Se non utilizzo il client e utilizzo una pagina asp.net per i risultati, funziona. –

8

Ho avuto un problema molto simile a quello che hai fatto. Ho scoperto che il proxy Entity Framework che avvolge le tue classi POCO è serializzato di default dal serializzatore WCF, che non può essere deserializzato sul lato client poiché il client non è a conoscenza del wrapper proxy EF. C'erano due soluzioni che ho trovato. Il primo è impostare ContextOptions.ProxyCreationEnabled su false. Ciò impedisce all'EF di creare proxy per gli oggetti POCO. Il secondo era di istruire WCF DataContractSerializer sul lato server per usare ProxyDataContractResolver per serializzare come solo il POCO.

La seconda opzione è disponibile al numero http://msdn.microsoft.com/en-us/library/ee705457.aspx. Da quando ho appena scoperto queste soluzioni non posso dire quale raccomando come pratica generale, sebbene mi riferisca a quest'ultima, poiché le query EF possono essere riutilizzate di volta in volta da altri chiamanti che potrebbero volere che gli oggetti vengano restituiti con i proxy EF appropriati. Comunque so che è tardi per questa domanda, ma spero che aiuti gli altri che si imbattono in questo problema.

+0

Grazie, usa la prima soluzione, aiuta molto – Dzmitry

+0

Grazie per le informazioni, è stato davvero utile –

3

È il .Incilla nella tua istruzione LINQ.

Credo che la ragione di ciò sia l'infrastruttura infinita risultante in modo sostanziale che punta da "un" lato al "molti" lato della relazione.

Questo si può osservare dal dispiegarsi tua datastructure, l'impostazione di un punto di interruzione il risultato della vostra istruzione di query .include nel debugger ...

Osservazione: Ordini -> Molti prodotti, ogni prodotto -> Ordine -> molti prodotti e così via

Immagino che wcf vi entri dentro e vi entri dentro.

di spezzare questa catena di, si può semplicemente evitare il puntamento indietro nel vostro oggetto di trasferimento dei dati aggiungendo l'ignoreDataMember Attributo

Nel lato molti della vostra relazione ... Nel tuo caso il prodotto .. ..

[IgnoreDataMember] public Order OrderFatherElement {get; impostato; }

In questo modo WCF si fermerà il serializingattempt quando si raggiunge che childnode

@microsoft .... certo potenziale di una correzione?

saluta,

Kieredin Garbaa