Custom handler on WCF is not working.

Topics: Exception Handling Application Block
Jan 26, 2012 at 3:24 PM

I’ve a custom handler. I’m using from Guy’s EchoService project.

I can’t seem to hit the break point in catch block catch (FaultException<ServiceException> e)

of unitTest1.cs TestMethod1. Can you please help?.

 

The log is configured for a flatfile and logs. Surprisingly it logs into the file but I can’t get into catch block. Please help

Please help. below is my config file. I've also sent the project to entlib.support@live.com with same subject line as this thread.


  <loggingConfiguration name="" tracingEnabled="true" defaultCategory="General">    <listeners>      <add name="Event Log Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FormattedEventLogTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FormattedEventLogTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"        source="AonHewitt.Cbt.Fusion" formatter="Text Formatter" log="Application"        machineName="." traceOutputOptions="DateTime, Timestamp" />      <add name="Flat File Trace Listener" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"        fileName="D:\Projects\EntLibFailing\WebApplication1\trace.log"        traceOutputOptions="Timestamp" />    </listeners>    <formatters>      <add type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"        template="Timestamp: {timestamp}{newline}&#xA;Message: {message}{newline}&#xA;Category: {category}{newline}&#xA;Priority: {priority}{newline}&#xA;EventId: {eventid}{newline}&#xA;Severity: {severity}{newline}&#xA;Title:{title}{newline}&#xA;Machine: {localMachine}{newline}&#xA;App Domain: {localAppDomain}{newline}&#xA;ProcessId: {localProcessId}{newline}&#xA;Process Name: {localProcessName}{newline}&#xA;Thread Name: {threadName}{newline}&#xA;Win32 ThreadId:{win32ThreadId}{newline}&#xA;Extended Properties: {dictionary({key} - {value}{newline})}"        name="Text Formatter" />    </formatters>    <categorySources>      <add switchValue="All" name="General">        <listeners>          <add name="Event Log Listener" />        </listeners>      </add>    </categorySources>    <specialSources>      <allEvents switchValue="All" name="All Events">        <listeners>          <add name="Flat File Trace Listener" />        </listeners>      </allEvents>      <notProcessed switchValue="All" name="Unprocessed Category">        <listeners>          <add name="Event Log Listener" />        </listeners>      </notProcessed>      <errors switchValue="All" name="Logging Errors &amp; Warnings">        <listeners>          <add name="Flat File Trace Listener" />        </listeners>      </errors>    </specialSources>  </loggingConfiguration>  <exceptionHandling>    <exceptionPolicies>      <add name="WCFShielding">        <exceptionTypes>          <add name="All Exceptions" type="System.Exception, mscorlib"            postHandlingAction="ThrowNewException">            <exceptionHandlers>              <add exceptionMessage="Service Fault Exception: The service operation threw an exception."                detailsExceptionType="Contracts.ServiceException, Contracts"                type="Services.ServiceFaultHandler, Services" name="Exception Translator" />            </exceptionHandlers>          </add>        </exceptionTypes>      </add>    </exceptionPolicies>  </exceptionHandling>  <system.web>    <compilation debug="true" targetFramework="4.0" />    <httpRuntime maxRequestLength="2147483646" />  </system.web>  <system.serviceModel>

Jan 27, 2012 at 5:19 AM

I suspect the issue is that the example uses the NetTcpBinding whereas you are using basicHttpBinding.  

Your solution has a few issues:

  • There is no need to use the ExceptionShielding attribute since you are not using exception shielding
  • If you proceed with your approach you need to use the try/catch/handle model:

                catch (Exception e)
                {
                    ExceptionPolicy.HandleException(e, "WCF Exception Shielding");
                    return null;
                }
    
  • You should be catching FaultException<ServiceException> and not FaultException<ServiceFault>

Even then it's not working.  The XML.  Let me reiterate that the custom handler that you are using was written before EntLib exception shielding.  I think exception shielding should do what you want.  If not, then why not?

Change the config file to use fault contract handler:

  <exceptionHandling>
    <exceptionPolicies>
      <add name="WCF Exception Shielding">
        <exceptionTypes>
          <add name="All Exceptions" type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
            postHandlingAction="ThrowNewException">
            <exceptionHandlers>
              <!--<add name="Logging Exception Handler" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                logCategory="General" eventId="100" severity="Error" title="Enterprise Library Exception Handling"
                formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling"
                priority="0" />-->
              <add type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.FaultContractExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF, Version=5.0.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                exceptionMessage="Service Fault Exception: The service operation threw an exception."
                faultContractType="Contracts.ServiceException, Contracts" name="Fault Contract Exception Handler" />
            </exceptionHandlers>
          </add>
        </exceptionTypes>
      </add>
    </exceptionPolicies>
  </exceptionHandling>

Use the exception shielding attribute:

    [ExceptionShielding]
    public class ManageService:IManageService
    {
    }

And then catch the exception:

try
{
    var s = new ManageServiceProxy();
    s.GetReleaseSnapshotData(2, 2);
}
catch (FaultException<ServiceException> e)
{
    var f = e.Detail;
    Console.WriteLine(f.MessageText + 1);
    //Console.WriteLine(f.detailsExceptionType);
}

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Jan 27, 2012 at 7:43 AM

Hi Randy,

 

Thank you for such a comprehensive explanation. Until now I'd not realised, the concept I was trying to implement was something before exceptionshileding. everything you've explained above makes complete sense and thanks for the same.

It works as expected for me. 

I wanted to use exceptionshileding as we do not intend to implement try-catch in our services. 

I'd posted few qns a week ago and I guess i'm already doing what I need to. I jsut need more members in my serviceException datacontract.

You're a star

 

Kavya

Jan 27, 2012 at 9:12 AM

Hi Randy, 

Just another question. 

I would still need to add more details into the mapping or pass exceptionType into the handler.  How can I do this?

I believe I still would need custom Handler?

Can you please guide me ?

Jan 27, 2012 at 9:15 AM

Please ignore my previous query. 

Jan 27, 2012 at 10:51 AM

Hi,

I thought this worked but not exactly.

with below config, 

 <exceptionHandlers>              <add type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.FaultContractExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF"  exceptionMessage="Service Fault Exception: The service operation threw an exception."  faultContractType="Contracts.ServiceException, Contracts" name="Fault Contract Exception Handler" />

it goes to 

 catch (FaultException e)

but not        catch (FaultException<ServiceException> e)

Is this obvious as there're no datamembers? or am I missing anything again? Please help.

I Either want to have ServiceException as my faultContract or below class as my faultcontract. if I use below class, can You help me understand how I can fill the Data Dictionary? I do not want to expose this as configurable property.  I believe I need customhandler? I essentially need to have more than just a Msg and Guid in my faultexception.

    [DataContract(Name = "ServiceFault")]
    public class ServiceFault
    {
        public ServiceFault()
        {

        }
        private string message;
        private IDictionary data;
        private Guid id;

        [DataMember]
        
        public string MessageText
        {
            get
            {
                return message;
            }
            set
            {
                message = value;
            }
        }

        [DataMember]
        public IDictionary Data
        {
            get
            {
                return data;
            }
            set
            {
                data = value;
            }
        }

        [DataMember]
        public Guid Id
        {
            get
            {
                return id;
            }
            set
            {
                id = value;
            }
        }
    }

Please help

Kavya

Jan 29, 2012 at 5:40 AM

If you are using a Service Reference then you should make sure you are catching a FaultException<ServiceReference.ServiceException> (or whatever your service proxy class is called) and not the actual server side ServiceException since those would be different classes.

If you are changing the ServiceException definition then also be sure to update the service reference.  I've seen it fall into the FaultException catch when the references haven't been updated.

As for the IDictionary problem I'm not sure I follow.  You want to populate an IDictionary without exposing it as a property?  If it's just mapping the exception Data property to your ServiceFault property then you can do that through configuration as a <mapping>.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Jan 30, 2012 at 7:42 AM

Hi Randy,

I'd not realised I'd to use ServiceReference.ServiceException. It makes sense. 

About the Data property, ignoring everything else I'd said, Yes I did try in mapping. like below. Unless I'm missing something, Neither Data nor innerException is being populated.

 
        [DataMember]
        public IDictionary Data
        {
            get
            {
                return data;
            }
            set
            {
                data = value;
            }
        }

        [DataMember]
        public Exception InnerException
        {
            get
            ;
            set;
        }
I'm hoping, if I populate these 2 properties, I don't need serviceException. Am I doing something wrong?

Feb 1, 2012 at 1:16 AM

Is the Data IDictionary and the InnerException populated on the original exception you are handling?  In my sample app it works OK.

--
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Feb 7, 2012 at 9:12 AM

Hi Randy,

 

The InnerException is populated. and I also tried StackTrace. not sure what I'm missing.

                <mappings>                  <add source="{Guid}" name="FaultId" />                  <add source="{Message}" name="FaultMessage" />                  <add source="{StackTrace}" name="Stacktrace" />                </mappings>

 

        [DataMember]        public Exception InnerException        {            get;set;                    }
        /// <summary>        /// stack Trace of an exception        /// </summary>        [DataMember]        public string Stacktrace        {            get;            set;        }

 

(I couldn't paste the code in the "insert code" window. it didn't work)

Feb 8, 2012 at 1:39 AM

I'm not 100% sure what you are experiencing but I would recommend not to pass back general Exceptions or IDictionary through your WCF interface.  Not only will you probably run into serialization issues but you are limiting interoperability as well.  For example if you try to return an InvalidCastException as the InnerException then WCF is going to complain:

Type 'System.InvalidCastException' with data contract name 'InvalidCastException:http://schemas.datacontract.org/2004/07/System' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.

If you really want to use WCF with an all .NET solution perhaps consider using the NetDataContractSerializer which includes CLR information in the generated XML and is quite powerful when the same .NET types exist on both sides of the wire.  Of course, this is not very interoperable.

 --
Randy Levy
Enterprise Library support engineer
entlib.support@live.com 

Feb 8, 2012 at 7:50 AM

Hi Randy,

Yes. I kinda faced this yesterday. 

to start with, ent lib was brand new to me. still is. so I started with a prototype and this is how I landed up. I wouldn't be catching inner exceptions in the datacontract.  nor the IData

the reason I put that in the code was to just check if any of the properties other than Guid and Messages are even caught.

My objective here essentially is to include little more information than just Guid or message. when the faultexception gets propogated to the client.although this information will not be shown to the client, UI developers will need bit more details than jsut one line error message and its guid.

your inputs would really help and would be very valuable.  I also need to log the errors at service end. i'm doing it now but at very basic level. need to attend this sometime soon

Kavya