3

I have created a simple test solution using Entity Framework and WCF. I have only one function in the service contract, called GetAllCustomers() that retrieves the customers from the database and returns them to the client. The client app calls the function and writes the customer names to the console.

When I call GetAllCustomers() from the client via proxy, I get a CommunicationException with the message,

An error occurred while receiving the HTTP response to http://localhost:8000/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.

The inner exception is System.Net.WebException:

The underlying connection was closed: An unexpected error occurred on a receive.

Next level of inner exception is System.IO.IOException:

Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.

And the final inner exception is System.Net.Sockets.SocketException:

An existing connection was forcibly closed by the remote host

Here is the client code:

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

Here is the host application code:

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

Here is the service library code for the function:

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

Strangely enough, if I bypass the database by replacing the foreach block with the commented out code below it, it works great!

I first thought it might be a timeout issue with the database query taking too long. However, my test code has a 45-second sleep in there, and it still returns the data to the client fine. The original code gives the exception after only about 3 seconds.

Also, if I call the original function (with the foreach block) by instantiating the WCF service directly, rather than via an endpoint/proxy, it also runs fine and returns all the customers in the database.

Lastly, I thought it might be an issue with the returned data set being too large, so I modified the foreach block and inserted a break statement after adding the first 5 customers to the results, and I still got the exception.

So, what else could be causing this?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
JoeMjr2
  • 3,804
  • 4
  • 34
  • 62
  • Is it Azure? How does the stack trace of innermost exception look like? How many entities does the CUSTOMER set (db.CUSTOMERs) have? The default timeout for SqlConnection is AFAIR 30 secs. If your query take longer than 30 secs the connection will be closed. You won't be able to repro this with a Sleep since there will be nothing that will break you query. How long does it take to run the corresponding query in the Db? – Pawel Dec 30 '12 at 09:00
  • No, it is not Azure. Both client and server are running on Windows 8. – JoeMjr2 Dec 30 '12 at 09:08
  • Stack trace of innermost exception is: 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) – JoeMjr2 Dec 30 '12 at 09:09
  • Query of the database itself takes about 2 seconds. There are about 12,000 customers in the database. – JoeMjr2 Dec 30 '12 at 09:10
  • The stacktraces are from the client app. Have you tried stepping through the server code when it's invoked by the client? With WCF if there is an unhandled exception in the service method, the client app will get this reponse. Step through the server code or create a FaultException on the service method and return the server error message to the client. – Quinton Bernhardt Dec 30 '12 at 10:58

3 Answers3

2

It's hard to tell what might be the problem. You could turn on WCF tracing and diagnostics which can give you some more details.

To get you going quickly - in your web (or app) config:

1) Add System.Diagnostics section anywhere under configuration element. You can replace path with which ever path you want the files to be stored at.

<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) Under system.ServiceModel add following:

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

3) Under C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\ start SvcTraceViewer.exe. Load both message trace (services_messages.svclog) and service trace log (services_tracelog.svclog). You can either drag drop files in the tool or open one then add another

4) Look for red bold letters for a problem.

If you want to make your experience editing the WCF configuration more palatable you can use SvcConfigEditor.exe which is found under same folder as SvcTraceViewer.exe (#3). Just open the config file and you should see Diagnostics folder which will allow you to start/stop and configure diagnostics.

Petar Vučetin
  • 3,555
  • 2
  • 22
  • 31
1

I think the problem was that the CUSTOMER type from Entity Framework contained sets (container types) of detail records (sales, etc.), which was making the data too big. I ended up creating a new type that didn't have those, and it worked fine after that.

John Saunders
  • 160,644
  • 26
  • 247
  • 397
JoeMjr2
  • 3,804
  • 4
  • 34
  • 62
0

if DataContext.ContextOptions.ProxyCreationEnabled = true changed to false

DataContext.ContextOptions.ProxyCreationEnabled = true

OR

return cloned Customer

public class Customer: ICloneable { Public int Id { get; set; }

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 (CUSTOMER c in db.CUSTOMERs) { 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;

}

zandi
  • 704
  • 5
  • 17