WCF and EHAB

Topics: Exception Handling Application Block
Dec 19, 2010 at 10:07 PM

Hi all, I'm trying to use EHAB for WCF but I have no success: probably I'm missing something stupid, could anyone help? Here's my scenario:

1) I define a service fault data contract like:

[DataContract]
public class ServiceFault
{
 [DataMember]
 public string MessageText { get; set; }

 [DataMember]
 public Guid Id { get; set; }
}

(BTW, what is exactly the Id mapped to the {Guid} source?)

2) I configure EHAB like:

<exceptionHandling>
 <exceptionPolicies>
  <add name="WcfPolicy">
   <exceptionTypes>
    <add name="All Exceptions"
       type="System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
       postHandlingAction="ThrowNewException">
     <exceptionHandlers>
      <add type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF.FaultContractExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.WCF, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
         faultContractType="Zax.Core.Services.ServiceFault, Zax.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
         name="Fault Contract Exception Handler">
       <mappings>
        <add source="{Guid}" name="Id" />
        <add source="{Message}" name="MessageText" />
       </mappings>
      </add>
     </exceptionHandlers>
    </add>
   </exceptionTypes>
  </add>
 </exceptionPolicies>
</exceptionHandling>

3) my service code is like:

[ServiceContract]
public interface IBookService
{
 [OperationContract]
 [FaultContract(typeof(ServiceFault))]
 IEnumerable<BookInfo> GetBooks();
}

4) its implementation:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ExceptionShielding("WcfPolicy")]
public class BookService : ZaxServiceBase, IBookService
{
 public IEnumerable<BookInfo> GetBooks()
 {
  FaultIfNotAuthenticated();
  return Repository.GetBooks();
 }
}

where FaultIfNotAuthenticated is inherited from the abstract base class ZaxServiceBase in the same assembly, which should return a fault if the service caller is not authenticated, like:

[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ExceptionShielding("WcfPolicy")]
public abstract class ZaxServiceBase
{
...
 protected void FaultIfNotAuthenticated()
 {
  if (!IsAuthenticated()) throw new AuthenticationException("Not authenticated");
 }
}

(BTW, do I need to repeat the ExceptionShielding attribute in this base class?)

5) clients wrap calls to these "secured" services in a catch(FaultException<ServiceFault>).

My problem is that when on the server side FaultIfNotAuthenticated throws its exception, this is not handled by EHAB and converted into a fault: if I step with the debugger I just get an unhandled exception popup rather than having the fault contract created and sent to the caller. What I'm missing here?

Also, I'd like to add more info in my fault contract, especially to let clients know if the fault was due to an authentication problem or not. This allows them to trying authenticating again, should their token have expired or the like, rather than giving up as with any other fatal error. Is there any viable property to map to when building the fault in my configuration?

Thanks!

Dec 20, 2010 at 2:44 AM

The {Guid} source is the HandlingInstanceId generated by EHAB.  For more info on what is the HandlingInstanceId, refer to this topic from the documentation.

On your next question, I'm not sure if you need to add it in the base class.  Could you try it out and see if it fixes your problem?  Because as of the moment, I can't see any problem with what you did.  You can also send a small repro for this so I could investigate it.

On your requirement on how to indicate to the client if the fault was due to an authentication problem or not, I would suggest adding an AuthenticationException to your WcfPolicy.  In your config, you only have "All Exceptions" defined in it.  If you add the specific AuthenticationException and have attached a FaultContractExceptionHandler as well to it, you would then be able to specify different message for each Exception Message property.  The exception message will then serve as the indication to the client code if it's an authentication problem or not.

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com

Dec 21, 2010 at 11:21 AM

Thank you very much for your reply!

I followed your advice and added a new exception type in my policy to handle authentication exceptions so that they can be caught in clients by catch(FaultException<AuthenticationServiceFault>).

Anyway, as for my issue it's still there: I'm posting a repro minimal project for you at the address of your signature, thank you in advance for any help. AFAIK, it seems there is some problem in loading the service fault handler at least in EL configuration editor: I can select my custom handler from my assembly, but it is marked by a red border with a message "unable to find type Zax.Core.Services.ServiceFault" etc., even if I correctly found and added it using the editor UI. Maybe the issue is there, but I cannot see why this happens.

As for the repro code: launch the ZaxTestClient console which just calls a service method (GetBooks) via a repository wrapper (which thus acts as the client code). This in turn calls GetBooks on the service proxy (in BookService.cs under ZaxEditWeb/Services); before doing its work, this method ensures that the client is authenticated by calling FaultIfNotAuthenticated, which simply returns false in this fake code, to simulate something like a security token expiration; this ends with throwing an AuthenticationException, which is NOT handled by EHAB.

Dec 22, 2010 at 3:09 AM

Here's what I did to get exception shielding to work on the project you sent.  First, I modified the config so that the WcfPolicy has 2 exception types.  For the AuthenticationException, I added a FaultContractExceptionHandler using the AuthenticationServiceFault as the FaultContract Type.  The second type is the All Exceptions which uses ServiceFault as the Fault Contract Type.  

Next, I specified the attribute [FaultContract(typeof(AuthenticationServiceFault))] attribute in your IBookService.GetBooks method since specifying it in the base class' FaultIfNotAuthenticated method doesn't work.  We need this because of the modification I made in the config.

Doing this allows me to catch the FaultException<AuthenticationServiceFault> in SvcRepository.GetBooks method.  However, when it rethrows, the exception, I still only get FaultException on the client side.  So the final step was to decorate the SvcRepository class with the [ExceptionShielding("WcfPolicy")] attribute and specify the [FaultContract(typeof(AuthenticationServiceFault))] attribute in its interface IZaxRepository.GetBooks method.

I'll send the modified project to you.

 

Sarah Urmeneta
Global Technologies and Solutions
Avanade, Inc.
entlib.support@avanade.com