WCF与实体框架错误第二部分

Out*_*per 5 wcf entity-framework

新手,请耐心等待,因为我昨天刚开始与WCF合作.

我使用Northwind获取数据,只向模型中添加了客户,订单,订单详细信息和产品,因此没什么特别的.

当我启动应用程序并调用Test并设置断点时,产品的值就在那里,并且它完成且没有错误.如果我然后尝试调用GetMaxQuantityByOrderID(10248),我会在底部列出错误.为什么Test()工作和相同的方法WITHIN Test()不起作用?我甚至添加了另一个(Test1(),与Test完全相同,除了它返回字符串:x.ProductName,它正确显示了Queso Cabrales).在另一个方法中调用的方法有效,但直接调用它会导致异常,这似乎很奇怪.

我遇到的另一个问题是IEnumerable GetOrders()仅在我添加.ToList()时才有效.如果没有它(或使用.AsEnumerable()),我会收到一个错误(ObjectContext实例已被释放,不能再用于需要连接的操作.),即使延迟加载设置为False.这背后的逻辑是什么?

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

错误:

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)
Run Code Online (Sandbox Code Playgroud)

Sha*_*rde 8

我和你有一个非常相似的问题.我发现包装POCO类的实体框架代理默认由WCF序列化程序序列化,由于客户端不知道EF代理包装器,因此无法在客户端进行反序列化.我找到了两种解决方案.第一种是将ContextOptions.ProxyCreationEnabled设置为false.这可以防止EF为您的POCO对象创建代理.第二个是指示服务器端的WCF DataContractSerializer使用ProxyDataContractResolver来序列化为POCO.

第二个选项可以在http://msdn.microsoft.com/en-us/library/ee705457.aspx找到.由于我刚刚发现了这些解决方案,我不能说我会推荐哪些作为一般做法,虽然我倾向于后者,因为EF查询可能会被其他调用者不时重复使用,可能希望返回的对象使用适当的EF代理.无论如何我知道这个问题已经晚了,但我希望能帮助其他遇到这个问题的人.


Lad*_*nka 1

对于第一个问题,请尝试在您的服务上打开WCF 跟踪。IEnumerable 的第二个问题是由延迟执行引起的。顺便提一句。您了解 IQueryable<T> 和 IEnumerable<T> 之间的区别吗?您是否知道您的 GetOrders 方法将所有订单、相关客户和产品加载到内存中?即使您想选择单个订单,您仍然可以将所有订单加载到服务中。

编辑:

WCF 跟踪将向您显示服务或客户端执行期间发生的情况 - 它跟踪 WCF 内部,是 WCF 开发的重要工具。有关 WCF 跟踪和跟踪查看器的教程。

IQueryable 构建表达式树,该树被编译为数据库查询,因此您无法在上下文范围(上下文负责数据库连接)之外执行该查询(延迟执行)。你必须重写你的方法。在您的情况下,每个方法都必须创建完整的查询并在上下文范围内执行该查询。查询的执行是通过选择单个记录(如 FirstOrDefault())或转换为列表来执行的。