3

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

当我GetAllCustomers()通过代理从客户端调用时,我收到一条CommunicationException消息,

接收对 的 HTTP 响应时出错http://localhost:8000/Service1。这可能是由于服务端点绑定未使用 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语句,我仍然得到了异常。

那么,还有什么可能导致这种情况?

4

3 回答 3

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\ 下启动 SvcTraceViewer.exe。加载消息跟踪 (services_messages.svclog) 和服务跟踪日志 (services_tracelog.svclog)。您可以在工具中拖放文件或打开一个然后添加另一个

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

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

于 2012-12-31T04:10:42.123 回答
1

我认为问题在于 Entity Framework 中的 CUSTOMER 类型包含详细记录(销售等)的集合(容器类型),这使得数据太大。我最终创建了一个没有这些的新类型,之后它运行良好。

于 2013-01-02T23:30:52.733 回答
0

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

DataContext.ContextOptions.ProxyCreationEnabled = true

或者

返回克隆客户

公共类客户:ICloneable { Public int Id { get; 放; }

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.CUSTOMERs 中的客户 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;

}

于 2012-12-31T04:40:06.450 回答