Exception Shielding not working

Topics: Exception Handling Application Block
Jun 13, 2013 at 1:39 PM
Hello there.

I've got a WCF project that is using EL 6 and I have set up exception shielding just as the documentation tells me to but it is not working. In fact, when the exception is thrown everything halts and nothing happens, not even an actual exception. I can't see anything that could be wrong, but I am using a self-hosted net.tcp WCF endpoint, not an IIS hosted one which, I presume, shouldn't be a problem.

I created a simple example that produces the same problem:
    [ServiceContract]
    public interface IService1
    {
        [OperationContract]
        [FaultContract(typeof(TestFault))]
        string GetData(int value);

        [OperationContract]
        [FaultContract(typeof(TestFault))]
        CompositeType GetDataUsingDataContract(CompositeType composite);
    }

    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }

    [DataContract]
    public class TestFault
    {
        [DataMember]
        public Guid FaultId
        {
            get;
            set;
        }

        [DataMember]
        public string FaultMessage
        {
            get;
            set;
        }
    }

    [ExceptionShielding("ServicePolicy")]
    public class Service1 : IService1
    {
        public string GetData(int value)
        {
            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;
        }
    }
I host it with a console host application that initialises the exception manager and then the actual host:
            List<ExceptionPolicyDefinition> policies = new List<ExceptionPolicyDefinition>();
            NameValueCollection mappings = new NameValueCollection();
            mappings.Add("FaultId", "{Guid}");
            mappings.Add("FaultMessage", "Doh!");

            List<ExceptionPolicyEntry> servicePolicy = new List<ExceptionPolicyEntry>()
            {
                {
                    new ExceptionPolicyEntry(typeof(Exception),
                        PostHandlingAction.None,
                        new IExceptionHandler[]
                        {
                            new FaultContractExceptionHandler(typeof(TestFault), mappings)
                        })
                }
            };
            policies.Add(new ExceptionPolicyDefinition("ServicePolicy", servicePolicy));
            ExceptionManager exceptionManager = new ExceptionManager(policies);
            ExceptionPolicy.SetExceptionManager(exceptionManager);

            host = new ServiceHost(typeof(Service1));
            host.Open();
This is my App.config on this console host:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="ExceptionShieldingTest.ServiceLibrary.Service1">
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://localhost:8733/" />
          </baseAddresses>
        </host>
        <endpoint address="net.tcp://localhost:8734/Service1" binding="netTcpBinding" bindingConfiguration="WindowsCredentialsServiceBinding" name="Service1_Tcp_Windows" contract="ExceptionShieldingTest.ServiceLibrary.IService1" />
        <endpoint address="Service1Mex" contract="IMetadataExchange" binding="mexTcpBinding" />
      </service>
    </services>
    <bindings>
      <netTcpBinding>
        <binding name="WindowsCredentialsServiceBinding" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" receiveTimeout="00:30:00" sendTimeout="00:15:00">
          <readerQuotas maxArrayLength="2147483647" />
          <reliableSession inactivityTimeout="3.00:00:00" enabled="true" />
          <security mode="Transport">
            <transport clientCredentialType="Windows" />
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
      <behaviors>
      <serviceBehaviors>
        <behavior>
          <serviceMetadata httpGetEnabled="False" httpsGetEnabled="False"/>
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

  <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
</configuration>
Finally, my console client application creates and uses a service client with this code:
            IService1 serviceClient = null;
            Uri serviceUrl = new Uri("net.tcp://localhost:8734/Service1");
            NetTcpBinding netTcpBinding = new NetTcpBinding();
            netTcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
            netTcpBinding.Security.Transport.ProtectionLevel = System.Net.Security.ProtectionLevel.EncryptAndSign;
            netTcpBinding.ReliableSession.InactivityTimeout = new TimeSpan(3, 0, 0, 0);
            netTcpBinding.ReliableSession.Enabled = true;

            EndpointAddress netTcpEndpoint = new EndpointAddress(serviceUrl);

            ChannelFactory<IService1> servicesFactory = null;

            try
            {
                servicesFactory  = new ChannelFactory<IService1>(netTcpBinding, netTcpEndpoint);
            }
            finally
            {
                if (servicesFactory != null)
                {
                    serviceClient = servicesFactory.CreateChannel();
                }
            }
            Console.WriteLine(serviceClient.GetData(2));
            try
            {
                serviceClient.GetDataUsingDataContract(null);
            }
            catch (FaultException<TestFault> ex)
            {
                Console.WriteLine("Caught the fault contract.");
                Console.WriteLine("Fault id: {0}\nFault message: {1}", ex.Detail.FaultId, ex.Detail.FaultMessage);
            }
            catch
            {
                Console.WriteLine("Caught something else.");
            }

            Console.WriteLine("Done");
Unfortunately, after the serviceClient.GetDataUsingDataContract(null); call everything stops and nothing seems to happen. I can debug the code going through the service and the line that throws the ArgumentNullException and that's it.

If I remove the attribute [ExceptionShielding("ServicePolicy")] from my Service1 class, I get an actual exception on the client side.

Any ideas of what might be going wrong?


Thanks!

P.S.: I can send this example project to an email address if need be.
Jun 14, 2013 at 8:35 AM
Thanks for providing a complete sample.

The problem looks to be that PostHandlingAction.None is used -- this says to swallow the exception which is why you never get anything back. You should change that to PostHandlingAction.ThrowNewException.

The only other thing is that the mappings have to be properties so you can't use a constant ("Doh!") there.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to
Jun 14, 2013 at 10:36 AM
Thanks, randylevy. I actually was trying something else when I posted this, but in the original code I am using PostHandlingAction.ThrowNewException and {Message} instead of "Doh!". :)

I have managed to make it work, but not with in-code set up of the exception policy. When it is set up in the App.config of my host application and I added the following code to my service's constructor, it worked:
            ExceptionHandlingSettings section = ConfigurationManager.GetSection(ExceptionHandlingSettings.SectionName) as ExceptionHandlingSettings;
            if (section != null)
            {
                exceptionManager = section.BuildExceptionManager();
            }
            ExceptionPolicy.SetExceptionManager(exceptionManager, false);
I still think there is something weird going on but if and when I get to the bottom of it I will post another reply.
Jun 14, 2013 at 2:23 PM
I copied and pasted your code and it is working fine for me. I just added the following to the end of the console host:
            var host = new ServiceHost(typeof(Service1));
            host.Open();

            Console.WriteLine("The service is ready");
            Console.WriteLine("Press <Enter> to stop the service.");
            Console.ReadLine();

            host.Close();
And as mentioned I changed the PostHandlingAction, and modified the app.config service name and contract to reflect my namespace.

SetExceptionManager only needs to be called once at application startup so you shouldn't put it in the service constructor.

Also, you could use the following code to read configuration from app.config instead of the posted code:
            ExceptionPolicy.SetExceptionManager(new ExceptionPolicyFactory().CreateManager());
If you post a sample solution it would be easier to see what the problem is.

~~
Randy Levy
entlib.support@live.com
Enterprise Library support engineer
Support How-to