6

I am just learning WCF, trying out different things.

I have set up the following service:

[ServiceBehavior(IncludeExceptionDetailInFaults = true , 
    InstanceContextMode = InstanceContextMode.Single)]
    public class TestService : ITestService
    {
        // This operation is defined as OneWay.
        public void Throws()
        {
            throw new ArgumentException();
        }
    }

I use it from my client like so:

var baseAddress = new Uri("net.pipe://localhost/hello");

// Create the ServiceHost.
using (ServiceHost host = new ServiceHost(typeof(TestService), baseAddress))
{
    var netBinding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None);
    host.AddServiceEndpoint(typeof(ITestService), netBinding, baseAddress);
    host.Open();

    Console.WriteLine("The service is ready at {0}", baseAddress);

    // Create client channel.
    var channel = ChannelFactory<ITestService>.CreateChannel(netBinding, new EndpointAddress(baseAddress));

    ((ICommunicationObject)channel).Open();

    try
    {
        foreach (var i in Enumerable.Range(0, 5000))
        {
            // channel dies after a few attempts.
            channel.Throws();
        }
    }

The method Throws is defined as IsOneWay = true, meaning it does not propogate any message back to the client (including errors).

When running in a loop, the communication object faults after some runs. I cannot figure out the cause of this.

The exception details:

System.ServiceModel.CommunicationException: There was an error writing to the pipe: The pipe is being closed. (232, 0xe8). ---> System.IO.PipeException: There was an error writing to the pipe: The pipe is being closed. (232, 0xe8). at System.ServiceModel.Channels.PipeConnection.StartSyncWrite(Byte[] buffer, Int32 offset, Int32 size, Object& holder) at System.ServiceModel.Channels.PipeConnection.Write(Byte[] buffer, Int32 offset, Int32 size, Boolean immediate, TimeSpan timeout, BufferManager bufferManage r) --- End of inner exception stack trace ---

Note that if i change the body of Throws method to something else, like Console.WriteLine, everything is running fine.

EDIT: I have uploaded the sample project to my SkyDrive: http://sdrv.ms/NumUbR

In case someone wants to compile it locally and see if it behaves the same.

lysergic-acid
  • 19,570
  • 21
  • 109
  • 218
  • One way operations can still fail if something is wrong with the connection, etc. They block until the service receives the entire message. Also, I believe hosting the service and invoking the client channel on the same thread could produce some interesting results.. – Jeremy Rosenberg Aug 13 '12 at 17:02
  • The service is not hosted on the same thread as far as i know. WCF takes care of spinning extra threads to monitor incoming calls, etc. The call to ServiceHost.Open blocks until the service host is opened, then moves on. – lysergic-acid Aug 13 '12 at 17:33
  • Also, the connection here is on the same machine, i am not sure what can go wrong in this small sample. – lysergic-acid Aug 13 '12 at 17:33
  • Can you add the remainder of the using block in the post, including the catch block? Also, have you tried hosting in a separate process from the client as a sanity check? – Jeremy Rosenberg Aug 13 '12 at 17:44
  • Tried separate processes. The client crashes with the same exception. Regarding the using statement - it just closes, there's nothing after that. – lysergic-acid Aug 13 '12 at 17:58
  • Once the channel faults, you need to create a new one (and ideally clean up the old one) – Jeremy Rosenberg Aug 13 '12 at 21:01
  • The question is -- why does it fault in this case? – lysergic-acid Aug 13 '12 at 21:04
  • I understand; I am looking into that. But I'm trying to cover other bases in the meantime which may be masking a different, more descriptive, error. Could you possibly post your code as a zip instead? – Jeremy Rosenberg Aug 13 '12 at 21:10
  • Updated the link in my original question to be a .zip file. – lysergic-acid Aug 13 '12 at 21:15

1 Answers1

5

You are simply exceeding the available bandwidth at some point. It’s likely the pipe, but it might also be in the WCF stack… processing exceptions is expensive and you are doing 5000 of them in as tight a loop as possible. Changing from an exception to a WriteLine() that returns nothing fixes the problem because it dramatically reduces the required bandwidth/processing. (I do see you mentioned OneWay, but I don't think it changes much. Even if the exception isn't returned, it still has to be processed).

Try changing InstanceContextMode to PerCall. That's the standard setting for “high volume” services. It will relieve some of the congestion.

Also to address the comments, hosting the service like this is fine. The ServiceHost will manage its own threads.

ErnieL
  • 5,773
  • 1
  • 23
  • 27
  • What bandwidth? It's failing after a very few number of calls (20 here). The pipe i/o is overlapped. What specifically is being exceeded here? – Jeremy Rosenberg Aug 13 '12 at 23:21
  • What's being exceeded is really a throttling question and the answer is: it depends. Take a look at the service I tuned and performance tested in this question. It talks about the series of limits I found. Notice how performance changes as the service does (or does not) move its work to a worker thread. http://stackoverflow.com/questions/7710220/wcf-performance-latency-and-scalability/7745600#7745600 – ErnieL Aug 14 '12 at 01:59