Problem using NotifyRethrow on a FaultException

Topics: Exception Handling Application Block
Feb 7, 2009 at 1:04 AM
Hi!

So here is my scenario: I have two services that utilize Exception Shielding and a WPF client that calls only one of these services - for discussion purposes, I'll call the service that my WPF client consumes ServiceA.  So when my client calls ServiceA, ServiceA in turn calls another service (ServiceB) that throws a FaultException<qReceiverFault> where 'qReceiver' is my own custom fault contract.  Without adding a FaultException to my config in ServiceA, the default Exception catches the FaultException from ServiceB and throws a new exception as defined in the exception handler.  But what I really would like to happen is for ServiceA to just pass the FaultException from ServiceB onto the client. 

So in my exception policy, I added a FaultException and set postHandlingAction="NotifyRethrow" as shown below:

<exceptionPolicies>
      <add name="AccountsSvcExceptionPolicy">
        <exceptionTypes>
          <add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
            postHandlingAction="ThrowNewException" name="Exception">
            <exceptionHandlers>
              <add logCategory="General" eventId="468" severity="Error" title="Enterprise Library Exception Handling"
                formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                priority="0" useDefaultLogger="false" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                name="DB Logging Handler" />
              <add exceptionMessage="" faultContractType="INS.Faults.Contracts.qReceiverFault, ins.faults.contracts, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null"
                type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.FaultContractExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
                name="qReceiverFault Contract Exception Handler">
                <mappings>
                  <add source="Message" name="Message" />
                  <add source="{guid}" name="FaultID" />
                </mappings>
              </add>
            </exceptionHandlers>
          </add>
          <add type="System.ServiceModel.FaultException`1[[INS.Faults.Contracts.qReceiverFault, ins.faults.contracts, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null]], System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
            postHandlingAction="NotifyRethrow" name="FaultException&lt;qReceiverFault&gt;" />
        </exceptionTypes>
      </add>
</exceptionPolicies>

However, when I do this I don't get FaultException<qReceiverFault> that I'm expecting from ServiceB back on the client, instead I get a generic FaultException that logs the following in ServiceA's database:

Timestamp: 2/7/2009 12:27:09 AM
Message: System.Configuration.ConfigurationErrorsException: The requested exception policy 'WCF Exception Shielding' could not be found.
   at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.EnterpriseLibraryFactory.BuildUp[T](IReadWriteLocator locator, ILifetimeContainer lifetimeContainer, String id, IConfigurationSource configurationSource)
   at Microsoft.Practices.EnterpriseLibrary.Common.Configuration.ObjectBuilder.LocatorNameTypeFactoryBase`1.Create(String name)
   at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicy.GetExceptionPolicy(Exception exception, String policyName, ExceptionPolicyFactory factory)
   at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicy.HandleException(Exception exceptionToHandle, String policyName, ExceptionPolicyFactory policyFactory)
   at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.ExceptionPolicy.HandleException(Exception exceptionToHandle, String policyName)
   at Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.ExceptionShieldingErrorHandler.ProvideFault(Exception error, MessageVersion version, Message& fault)
Category: General
Priority: -1
EventId: 1
Severity: Information


Now if I set the postHandlingAction="ThrowNewException" on my FaultException<qReceiverFault> in ServiceA, then my client will get a new exception.  But I really want the original FaultException<qReceiverFault> from ServiceB.  Is there a way to simply pass on a FaultException through without having to throw a new exception??  Any help or ideas would be greatly appreciated.

thanks,
Ramiro
Feb 9, 2009 at 5:06 AM

Hi,

Regarding the error that was logged from your ServiceA, It seems that you dont have a exception policy defined named 'WCF Exception Shielding'. try to resolve that first and see what happens.

Valiant Dudan
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Feb 9, 2009 at 5:20 PM
Edited Feb 9, 2009 at 6:02 PM
Yes, I've already verified that.  I only have one policy called 'AccountsSvcExceptionPolicy' and my Service Implementation class has the ExceptionShielding attribute with the exact same name as shown below:


<exceptionHandling>
    <exceptionPolicies>
      <add name="AccountsSvcExceptionPolicy">
        <exceptionTypes>
        ....

</exceptionHandling>        

       
[ExceptionShielding("AccountsSvcExceptionPolicy")]
public class AccountsService : IAccountsManagerService


I believe the 'WCF Exception Shielding' policy seems to be a generic name that Enterprise Library is looking when a name isn't specified in the ExceptionShielding attribute.  Since I only have one policy and I've defined in correctly in the ExceptionShielding attribute, I'm now sure why EnterpriseLibrary is looking for the generic name...

Feb 10, 2009 at 3:00 AM
Yes, the "WCF Exception Shielding" is the name which is being looked up if you didn't specify any exception policy in the ExceptionShielding attribute.  In contrast with you though, I'm not sure why EnterpriseLibrary is looking for that policy if you did specify the "AccountsSvcExceptionPolicy" in the ExceptionShielding attribute.  In addition, what happens now to your app? Is it working now?  Or are you getting a new exception?


Sarah Urmeneta
Global Technology & Solutions
Avanade, Inc.
entlib.support@avanade.com
Feb 10, 2009 at 5:17 AM

I guess I should have been more clear in my last response.  I didn't change anything because I verified the policy name in my config file and source code before I created this post.  In other words, I'm not seeing a new problem - I'm having the same issue that I initially submitted.  I'm really puzzled as to why EnterpriseLibrary is looking for the 'WCF Exception Shielding' policy when I have the 'AccountsSvcExceptionPolicy' policy already defined in both my config file and source code.

 

Feb 10, 2009 at 5:50 AM
Do both ServiceA and Service b has the ExceptionShielding attribute with an explicit policy name? Check both because you might be assuming it's occuring on the other when actually it's caused by the other one.


Sarah Urmeneta
Global Technology & Solutions
Avanade, Inc.
entlib.support@avanade.com
Feb 10, 2009 at 4:03 PM
Yes, both ServiceA and ServiceB each have one explicit policy name.  ServiceA's policy is called 'AccountsSvcExceptionPolicy' and ServiceB's policy is called 'NumberingSvcExceptionPolicy'. And the exception shielding attribute for each service matches the policy name in each respective config file.
Feb 11, 2009 at 7:51 AM
Hi,

if you want you client to recieve the FaultException<> , you must specify the "includeExceptionDetailInFaults" in your web config to true, i tried your scenario. I have 2 WCF App, Added ExceptionShielding attribute to the interface, together with the policy name. In the config, i used NotifyRethrow. then i got the FaultException<> in my client. 

Valiant Dudan
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com
Feb 12, 2009 at 4:11 AM
Setting 'includeExceptionDetailInFaults'  to "true" may be okay in a development environment, but I would never set that to "true" in my production environment because I don't want to send back unsafe exceptions or stack traces back to the client.  However, I tried that just to test and this didn't work anyway...

Feb 12, 2009 at 4:22 AM
Edited Feb 12, 2009 at 5:00 AM
The error message is very clear but I agree, I'm also wondering why would it look for that policy.  Could you send a small project which repro the error? I can't repro it.  In addition, have you ever had your app running before encountering that error?

I would also suggest that you explicitly add that policy and see what happens.

Sarah Urmeneta
Global Technology & Solutions
Avanade, Inc.
entlib.support@avanade.com
Feb 12, 2009 at 5:44 AM
I tried out this one, I stick to the ThrowNewException PostHandlingAction and the client was able to catch the FaultException<qReceiverFault>.  I could send you the solution if you like.


Sarah Urmeneta
Global Technology & Solutions
Avanade, Inc.
entlib.support@avanade.com
Feb 12, 2009 at 4:56 PM

Hi Sarah,

As I mentioned in my original post, if I set the postHandlingAction="ThrowNewException" on my FaultException<qReceiverFault> in ServiceA, then my client will get a FaultException.  But not the original FaultException<qReceiverFault> from ServiceB that I need so that the client can see the FaultID.

 

Feb 13, 2009 at 7:07 AM
Hi,

After some tries, i finally have it worked. I can now get the faultId which is from the serviceB on the client. I'm using the NotifyRethrow on both Service. and the "includeExceptionDetailInFaults" set to "false". I could send you the sample solution that i have if you like.


Valiant Dudan
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com

Feb 13, 2009 at 4:04 PM
Sure, that would be great!  I'll send you an email from my personal email account shortly...

thanks!
Mar 11, 2009 at 7:59 PM
Can you repost the solution code here?  I am having a bit of the same issues.
Mar 12, 2009 at 3:29 AM
Here is the code from ServiceB:

public void DoSomething()
{
\    
try
    
{
        MyFault fault = new MyFault();
        fault.Id =
Guid.NewGuid();
        fault.MessageText =
"Fake Reason";
        
FaultReason reason = new FaultReason(new FaultReasonText("Another fake reason."));
        
throw new FaultException<MyFault>(fault, reason);
    }
    
catch(Exception ex)
    {
        
bool rethrow = ExceptionPolicy.HandleException(ex, "WCF Exception Shielding");
        
if (rethrow)
        {
            throw;
        }
    }
}

 


The code from Service A simply creates an instance of Service B and calls this method inside a try catch statement.  The client creates an instance of Service A and calls that method which calls this method, also inside a try catch statement.

Sarah Urmeneta
Global Technology and Solutions
Avanade, Inc.
entlib.support@avanade.com
Jun 10, 2011 at 3:47 PM
Edited Jun 10, 2011 at 3:50 PM

Hi Sarah,

Regarding your last post, I have a question for you:

does your solution imply that I don't have to decorate the service implementation class with the ExceptionShielding attribute?

I think that the strength of EntLib Exception Shielding is just the fact that you don't need to force a developer to add a try-catch block to a service method, as all the exception handling for faults is applied "behind the scenes" through a WCF behavior.

Is there any alternative to your solution that still uses configuration instead of coding a try-catch block in service methods?

Thanks, regards

Jun 13, 2011 at 6:39 AM

Hi,

I tried looking at the sample solution and I just noticed that ServiceB's implementation class is indeed have ExceptionShielding attribute. It's just happened that ServiceA is using the normal reference (not the Service Reference) to ServiceB. The exception shielding won't work here that's why she created a FaultException<MyFault> and throw it so that ServiceA will catch it as is. I tried using service reference ServiceB from ServiceA to make exception shielding work but I got some reference errors. I'm not even sure if nesting WCF service is even possible or maybe I'm just missing something. But basically, you don't need to add try & catch to your service method.

 

Noel Angelo Bolasoc
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com