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

时间:2010-08-19 00:48:51

标签: wcf entity-framework

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

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

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

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

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

错误:

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)

3 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分:3)

你的LINQ语句中的.Inculde。

我认为这样做的原因是基本产生的无限数据结构指向和从你的关系的“一”侧到“多”侧。

您可以通过展开数据结构,在调试器中的.Include查询语句的结果处设置断点来观察...

观察: 订单 - &gt;许多产品,每种产品 - &gt;订单 - &GT;许多产品等等

我想wcf会遇到这种情况并加强其中。

要打破这一链条,您可以简单地避免指向数据传输对象 通过添加ignoreDataMember属性

在你们关系的多方面......在你的情况下,产品......

[IgnoreDataMember] 公共秩序OrderFatherElement {get;组; }

这样WCF将在到达该子节点时停止序列化尝试

@microsoft ....修复的一些潜力?

迎接,

Kieredin Garbaa

答案 2 :(得分:1)

对于第一个问题,请尝试在您的服务上启用WCF tracing。 IEnumerable的第二个问题是由自定义执行引起的。顺便说一句。你了解IQueryable&lt; T&gt;之间的区别吗?和IEnumerable&lt; T&gt;?您是否知道您的GetOrders方法将所有订单,相关客户和产品加载到内存中?即使您想要选择单个订单,您仍然会在服务中加载所有订单。

修改:

WCF跟踪将向您展示服务或客户端执行期间发生的事情 - 它跟踪WCF内部,它是WCF开发的必要工具。有关WCF跟踪和trace viewer的教程。

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