Question

I am trying to implement IErrorHandler in the WCF services that uses iis and net.tcp.

I set a scenario to throw DivideByZeroException in the server. IErrorHandler is firing as expected.

The FaultException is not returning to client and I am getting timeout exception. I could not find any info/exception in event log also.

Here is the demo code. http://www.fileswap.com/dl/gQFlVsZK7M/ (Please click on slow download image)

EDIT 1 (added code from archive for all to see it):

Service contract:

[ServiceContract]
public interface IService1
{

    [OperationContract]
    [FaultContract(typeof(DivideByZeroException))]
    string GetData(int value);

    [OperationContract]
    [FaultContract(typeof(DivideByZeroException))]
    CompositeType GetDataUsingDataContract(CompositeType composite);

    // TODO: Add your service operations here
}

Service Implementation:

public class Service1 : IService1
{
    public string GetData(int value)
    {
        int i = 0;

        //division by zero!
        int y = 10/i;
        return string.Format("You entered: {0}", value);
    }

    public CompositeType GetDataUsingDataContract(CompositeType composite)
    {
        if (composite == null)
        {
            throw new ArgumentNullException("composite");
        }
        if (composite.BoolValue)
        {
            composite.StringValue += "Suffix";
        }
        return composite;
    }
}

IErrorHandler implementation:

public class WcfErrorHandler : IErrorHandler
{
    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        var v = error as DivideByZeroException;
        if (v != null)
            fault = Message.CreateMessage(
                version,
                new FaultException<DivideByZeroException>(v, new FaultReason(v.Message)).CreateMessageFault(),
                "http://the.fault.action");
    }

    public bool HandleError(Exception error)
    {
        return true;
    }
}
Was it helpful?

Solution

You ServiceReference in ConsoleApplication1 is not updated and does not contain fault contract attribute. As you use .NET for the service and client it's better to share DataContract and ServiceContract between them.

For the test you can reference WcfService1 library in your ConsoleApplication1 application. When you do that, follow steps:

  1. app.config in ConsoleApplication1:

    <client>
    
      <endpoint address="net.tcp://localhost/WcfService1/Service1.svc"
        binding="netTcpBinding"
        contract="WcfService1.IService1" name="NetTcpBinding_IService2">
      </endpoint>
    
    </client>
    
  2. Client code:

    try
    {
        var fact = new ChannelFactory<WcfService1.IService1>("NetTcpBinding_IService2");
        var proxy = fact.CreateChannel();
        var ves = proxy.GetData(1);
        Console.WriteLine(ves);
    
    }
    catch (FaultException<DivideByZeroException> exp)
    {
        Console.WriteLine(exp.Detail);
    }
    
  3. Service code (I prefer to catch exception as much closer to code causing it as possible and then throws a concrete fault exception):

    public string GetData(int value)
    {            
        try
        {
            int i = 0;
            int y = 10/i;
            return string.Format("You entered: {0}", value);
        }
        catch (DivideByZeroException d)
        {
            throw new FaultException<DivideByZeroException>(d);
        }
    }
    
  4. Your IErrorHandler:

    public class WcfErrorHandler : IErrorHandler
    {
        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
        {
    
            if (error is FaultException)
            {
                //do nothing as it's already FaultException
                //you should do a transformation only in the case it's required
            }
            else
            {
                // Generate fault message manually including the exception as the fault detail
                MessageFault messageFault = MessageFault.CreateFault(
                    new FaultCode("Sender"),
                    new FaultReason(error.Message),
                    error);
                fault = Message.CreateMessage(version, messageFault, null);
            }
        }
    
        public bool HandleError(Exception error)
        {
            //here you can log an exception
            return true;
        }
    }
    

P.S. It seems you have hosted your service incorrectly. To test it, I've referenced WcfService1 in ConsoleApplication1. And did following:

  1. Added such lines into app.config of ConsoleApplication1:

    <services>
      <service name="WcfService1.Service1" behaviorConfiguration="CalculatorServiceBehavior">
        <endpoint address="" binding="netTcpBinding" contract="WcfService1.IService1" />
        <!--<endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" /> -->
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost/WcfService1/Service1.svc"/>
          </baseAddresses>
        </host>
      </service>
    </services>
    
    <behaviors>
      <serviceBehaviors>
        <behavior name="CalculatorServiceBehavior">
          <serviceDebug includeExceptionDetailInFaults="True" />
          <errorHandler />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    
    <extensions>
      <behaviorExtensions>
        <add name="errorHandler" type="WcfService1.ErrorHandlerExtension, WcfService1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
      </behaviorExtensions>
    </extensions>
    
  2. And before making a call to the service by client, I've started service:

    private static void Main(string[] args)
    {
       var host = new ServiceHost(typeof(WcfService1.Service1));
       host.Open();
       ... 
    
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top