views:

64

answers:

2

I have a WCF service that's hosted in IIS, and uses a WS HTTP binding (the external service). This service ends up calling a second WCF service that's hosted in a Windows service, over Net TCP (the internal service). When the internal service throws a FaultException, the external service crashes rather than throwing it to the client. All the client sees is the connection being forcibly closed.

The internal service uses the Enterprise Library Validation Application Block to validate the incoming messages. When validation errors occur, the service throws a FaultException<ValidationFault>.

Both the internal and external service have a [FaultContract(typeof(ValidationFault)] attribute in the service contract. If I change the external service to just immediately throw a new FaultException<ValidaitonFault>, this gets back to the client fine. I can catch the exception from the internal service in the external service, but if I try to re-throw it, or even wrap it in a new exception and throw that, the whole Application Pool in IIS crashses. I can't see anything useful in the event log, so I'm not sure exactly what the problem is.

The client object the external service uses to communicate with the internal service is definitely being closed and disposed of correctly. How can I get the internal service's faults to propagate out to the client?

updated:

Below is a simplified version of the external service code. I can catch the validation fault from the internal service call. If I throw a brand new FaultException<ValidationFault>, everything is fine. If I use the caught exception, the connection to the external client is broken. The only difference I can see is when debugging the service - trying to use the caught exception results in a message box appearing when exiting the method, which says

An unhandled exception of type 'System.ServiceModel.FaultException`1' occurred in mscorlib.dll

This doesn't appear if I throw a brand new exception. Maybe the answer is to manually copy the details of the validation fault into a new object, but this seems crazy.

public class ExternalService : IExternalService
{
   public ExternalResponse DoSomething(ExternalRequest)
   {
      try
      {
         var response = new ExternalResponse();
         using (var internalClient = new InternalClient())
         {
            response.Data = internalClient.DoSomething().Data;
         }

         return response;
      }
      catch (FaultException<ValidationFault> fEx)
      {
         // throw fEx;   <- crashes

         // throw new FaultException<ValidationFault>(
         //    fEx.Detail as ValidationFault);   <- crashses

         throw new FaultException<ValidationFault>(
            new ValidationFault(new List<ValidationDetail> {
               new ValidationDetail("message", "key", "tag") }),
               "fault message", new FaultCode("faultCode"))); // works fine!
      }
   }
}
A: 

I have almost the exact design as you and hit a similar issue (not sure about a crash, though!).

If I remember correctly, even though the ValidationFault is a common class when the Fault travels over the wire the type is specific to the WCF interface. I think this is because of the namespace qualifiers on the web services (but this was a while back so I could be mistaken).

It's not terribly elegant, but what I did was to manually re-throw the exceptions:

try
{
    DoStuff();
}
catch (FaultException<ValidationFault> fe)
{
    HandleFault(fe);
    throw;
}

...

private void HandleFault(FaultException<ValidationFault> fe)
{
    throw new FaultException<ValidationFault>(fe.Detail as ValidationFault);
}
Tuzo
Thanks for the suggestion, but unfortunately it didn't work. I've added some more details to the question if that's any use.
Graham Clark
A: 

Well, it works if I do this, but there must be a better way...

This only seems to be a problem for FaultException<ValidationFault>. I can re-throw FaultException and FaultException<SomethingElse> objects with no problems.

try
{
   DoStuff();
}
catch (FaultException<ValidationFault> fe)
{
   throw this.HandleFault(fe);
}

...

private FaultException<ValidationFault> HandleFault(
    FaultException<ValidationFault> fex)
{
    var validationDetails = new List<ValidationDetail>();
    foreach (ValidationDetail detail in fex.Detail.Details)
    {
        validationDetails.Add(detail);
    }

    return new FaultException<ValidationFault>(
        new ValidationFault(validationDetails));
}
Graham Clark