【问题标题】:WCF with Entity Framework Error Part II带有实体框架错误的 WCF 第 II 部分
【发布时间】:2013-07-30 20:44:35
【问题描述】:

新手,请多多包涵,因为我昨天刚开始使用 WCF。

我使用 Northwind 来获取数据,并且只在模型中添加了客户、订单、订单详细信息和产品,所以没什么特别的。

当我启动应用程序并调用 Test 并设置断点时,products 的值就在那里,并且它在没有错误的情况下完成。如果我随后尝试调用 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)

【问题讨论】:

    标签: wcf entity-framework


    【解决方案1】:

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

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

    【讨论】:

    • 谢谢,使用第一个解决方案,非常有帮助
    • 感谢您的信息,非常有帮助
    【解决方案2】:

    它是 .Inculde 在您的 LINQ 语句中。

    我相信造成这种情况的原因基本上是无限数据结构指向和从你的关系的“一”端到“多”端。

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

    观察: 订单 --> 许多产品,每个产品--> 订单--> 许多产品等等

    我猜 wcf 遇到了这个问题并被咳了出来。

    要打破这个链条,你可以简单地避免在你的数据传输对象中指向回来 通过添加 ignoreDataMember 属性

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

    [忽略数据成员] 公共秩序 OrderFatherElement { 得到;放; }

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

    @microsoft.... 有修复的可能吗?

    你好,

    基雷丁·加尔巴

    【讨论】:

      【解决方案3】:

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

      编辑:

      WCF 跟踪将向您展示在服务或客户端执行期间发生了什么 - 它跟踪 WCF 内部,它是 WCF 开发的重要工具。 WCF 追踪教程和trace viewer

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

      【讨论】:

      • 如果我更改为 IQueryable,我会收到错误 ObjectContext 实例已被释放,不能再用于需要连接的操作。进行 WCF 服务的正确方法是什么?我不明白配置跟踪将允许我做什么。正如我所说,我 2 天前才开始使用 WCF。
      • 该问题仅出现在 WCF 测试客户端中。如果我不使用客户端并使用 asp.net 页面获取结果,它可以工作。
      • 然后打开 WCF 跟踪并检查它在测试客户端中失败的原因。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多