从Entity Framework返回结果时,WCF调用失败

时间:2012-12-30 08:34:37

标签: wcf entity-framework communicationexception

我使用Entity Framework和WCF创建了一个简单的测试解决方案。我在服务合同中只有一个函数,称为GetAllCustomers(),它从数据库中检索客户并将它们返回给客户端。客户端应用程序调用该函数并将客户名称写入控制台。

当我通过代理从客户端拨打GetAllCustomers()时,我会收到CommunicationException的消息,

  

收到http://localhost:8000/Service1的HTTP响应时发生错误。这可能是由于服务端点绑定不使用HTTP协议。这也可能是由于服务器中止HTTP请求上下文(可能是由于服务关闭)。有关详细信息,请参阅服务器日志。

内部异常是System.Net.WebException

  

基础连接已关闭:接收时发生意外错误。

内部异常的下一级是System.IO.IOException

  

无法从传输连接读取数据:远程主机强行关闭现有连接。

最后的内部异常是System.Net.Sockets.SocketException

  

远程主机强行关闭现有连接

以下是客户端代码:

static void Main(string[] args)
{
    Console.WriteLine("Press Enter to begin.");
    Console.ReadLine();

    ServiceReference1.Service1Client MyService = new ServiceReference1.Service1Client();

    CUSTOMER[] cl = MyService.GetAllCustomers();

    foreach (CUSTOMER c in cl)
    {
        Console.WriteLine(c.CUSTFNAME + " " + c.CUSTLNAME);
    }

    Console.WriteLine("Press Enter to exit.");
    Console.ReadLine();
}

这是主机应用程序代码:

static void Main(string[] args)
{
    ServiceHost hostA = null;

    try
    {
        hostA = new ServiceHost(typeof(Service1), new Uri("http://localhost:8000") );
        hostA.AddServiceEndpoint(typeof(IService1), new BasicHttpBinding(), "Service1");

        hostA.Open();

        Console.WriteLine();
        Console.WriteLine("Host started.  Press Enter to terminate host.");
        Console.ReadLine();

    }
    finally
    {
        if (hostA.State == CommunicationState.Faulted)
            hostA.Abort();
        else
            hostA.Close();
    }
}

以下是该功能的服务库代码:

public HashSet<CUSTOMER> GetAllCustomers()
{
    var db = new TRS11Entities();

    HashSet<CUSTOMER> TheCusts = new HashSet<CUSTOMER>();

    foreach (CUSTOMER c in db.CUSTOMERs)
    {
        TheCusts.Add(c);
    }

    //CUSTOMER TestCust1 = new CUSTOMER();
    //TestCust1.CUSTFNAME = "Joe";
    //TestCust1.CUSTLNAME = "Schmoe";
    //CUSTOMER TestCust2 = new CUSTOMER();
    //TestCust2.CUSTFNAME = "Peter";
    //TestCust2.CUSTLNAME = "Pumpkineater";
    //TheCusts.Add(TestCust1);
    //System.Threading.Thread.Sleep(45000);
    //TheCusts.Add(TestCust2);

    return TheCusts;
}

奇怪的是,如果我通过用下面注释掉的代码替换foreach块来绕过数据库,它就会很棒!

我首先认为这可能是数据库查询耗时太长的超时问题。但是,我的测试代码在那里有45秒的睡眠时间,它仍然可以将数据返回给客户端。原始代码仅在约3秒后给出异常。

此外,如果我通过直接实例化WCF服务而不是通过端点/代理来调用原始函数(使用foreach块),它也可以正常运行并返回数据库中的所有客户。

最后,我认为这可能是返回数据集太大的问题,所以我修改了foreach块并在将前5个客户添加到结果后插入了break语句,我仍然得到了异常。 / p>

那么,还有什么可能导致这个?

3 个答案:

答案 0 :(得分:2)

很难说出问题所在。您可以启用WCF跟踪和诊断,这可以为您提供更多详细信息。

为了让您快速上手 - 在您的网络(或应用)配置中

1)在配置元素下的任何位置添加System.Diagnostics部分。您可以将路径替换为您希望存储文件的路径。

<system.diagnostics>
    <sources>
      <source name="System.ServiceModel.MessageLogging" switchValue="Warning, ActivityTracing">
        <listeners>
          <add type="System.Diagnostics.DefaultTraceListener" name="Default">
            <filter type="" />
          </add>
          <add name="ServiceModelMessageLoggingListener">
            <filter type="" />
          </add>
        </listeners>
      </source>
      <source name="System.ServiceModel" switchValue="Warning, ActivityTracing" propagateActivity="true">
        <listeners>
          <add type="System.Diagnostics.DefaultTraceListener" name="Default">
            <filter type="" />
          </add>
          <add name="ServiceModelTraceListener">
            <filter type="" />
          </add>
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add initializeData="C:\temp\services_messages.svclog" type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="ServiceModelMessageLoggingListener" traceOutputOptions="LogicalOperationStack, DateTime, Timestamp, ProcessId, ThreadId, Callstack">
        <filter type="" />
      </add>
      <add initializeData="C:\temp\services_tracelog.svclog" type="System.Diagnostics.XmlWriterTraceListener, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="ServiceModelTraceListener" traceOutputOptions="LogicalOperationStack, DateTime, Timestamp, ProcessId, ThreadId, Callstack">
        <filter type="" />
      </add>
    </sharedListeners>
  </system.diagnostics>

2)在system.ServiceModel下添加以下内容:

<diagnostics wmiProviderEnabled="false">
      <messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" />
    </diagnostics>

3)在C:\ Program Files(x86)\ Microsoft SDKs \ Windows \ v7.0A \ Bin \ start SvcTraceViewer.exe下。加载消息跟踪(services_messages.svclog)和服务跟踪日志(services_tracelog.svclog)。您可以在工具中拖放文件或打开文件,然后添加另一个

4)找出问题的红色粗体字母。

如果您想让编辑WCF配置的体验更加可口,可以使用SvcConfigEditor.exe,它位于与SvcTraceViewer.exe(#3)相同的文件夹下。只需打开配置文件,您就会看到Diagnostics文件夹,它允许您启动/停止和配置诊断。

答案 1 :(得分:1)

我认为问题是来自实体框架的CUSTOMER类型包含详细记录(销售等)的集合(容器类型),这使得数据太大。我最终创建了一个没有那些的新类型,之后它运行良好。

答案 2 :(得分:0)

如果DataContext.ContextOptions.ProxyCreationEnabled = true更改为false

DataContext.ContextOptions.ProxyCreationEnabled = true

OR

返回克隆客户

公共类客户:ICloneable    {     Public int Id                   {                      得到;                      组;                   }

public object Clone()
 {
     var cloneObject = new Customer();
      cloneObject.Id=this.Id; 
      return cloneObject;
 }

}

public HashSet GetAllCustomers()  {     var db = new TRS11Entities();     HashSet TheCusts = new HashSet();     foreach(db.CUSTOMER中的CUSTOMER c)     {         TheCusts.Add(c.Clone());     }

//CUSTOMER TestCust1 = new CUSTOMER();
//TestCust1.CUSTFNAME = "Joe";
//TestCust1.CUSTLNAME = "Schmoe";
//CUSTOMER TestCust2 = new CUSTOMER();
//TestCust2.CUSTFNAME = "Peter";
//TestCust2.CUSTLNAME = "Pumpkineater";
//TheCusts.Add(TestCust1);
//System.Threading.Thread.Sleep(45000);
//TheCusts.Add(TestCust2);

return TheCusts;

}