Rethrowing strongly-typed WCF FaultException in a middle-layer service - wcf

I have a very simple 3-tier project. There is a DAL (data access layer) WCF service interacting with a data store; a BLL (business logic layer) WCF service as an intermediary between the DAL service and a client UI, and a Windows Forms client layer.
I declare a DataContract in my DAL service to act as a fault contract:
[DataContract]
public class ValidationFault
{
[DataMember]
public String Message { get; set; }
[DataMember]
public String PropertyName { get; set; }
...
}
My DAL service has an operation decorated with a FaultContract attribute:
[OperationContract]
[FaultContract(typeof(ValidationFault))]
Patient CreatePatient(Patient patient);
The implementation of CreatePatient throws a strongly-typed FaultException like this:
throw new FaultException<ValidationFault>(new ValidationFault("Patient last name cannot be empty.", "LastName"));
My BLL service acts as a client for the DAL service, and a service for the UI layer. In my BLL service I call the CreatePatient method of the DAL service, and if I catch the FaultException fault, I simply want to re-throw it to be handled by the client. The relevant BLL code looks like this:
...
catch (FaultException<ValidationFault>)
{
throw;
}
I can inspect the exception in the BLL and can confirm that it is a strongly-typed FaultException and the Detail section passed from the DAL intact. The BLL method attempting to rethrow the exception is decorated with the same [FaultContract] attribute as the DAL method above.
The UI client, which is a client of the BLL service, tries to handle the exception and log/display the appropriate information. Trouble is, when this fault reaches the client, it is no longer a strongly-typed FaultException, but instead a general FaultException with a null Detail section.
I did find that if instead of just rethrowing the fault in the BLL method, I instead recreate it with the same parameters like this:
catch (FaultException<ValidationFault> valEx)
{
throw new FaultException<ValidationFault>(new ValidationFault(valEx.Detail.Message, valEx.Detail.PropertyName));
}
then it reaches the client as a strongly-typed FaultException as expected.
My question is: why do I need to recreate this exception in the BLL service? Why can't I just pass through the strongly-typed FaultException thrown by the DAL service? I got the code to work but would like to understand what is going on. I imagine it's something that's staring me in the face but I can't for the life of me figure it out.

Indeed the answer was staring me in the face all along, so in case this helps someone down the road: my problem was the Action property of the FaultContract. When you decorate an operation with the FaultContract attribute, unless you specify Action explicitly, WCF automatically generates it for you. This Action includes the FaultException namespace, as well as the service and method names of the operation that generated the fault. In my case, the service and method name in my BLL layer were different than the service and method name of my DAL method that originally generated the exception, so although both my DAL and my BLL layer operations were decorated with an identical attribute:
[FaultContract(typeof(ValidationFault))]
... the Action of the FaultContract was different. Thus when trying to rethrow the DAL FaultException in the BLL service, the FaultContract did not match the one specified on the BLL operation, and WCF was repacking the exception as a general FaultException instead of a strongly-typed one.
My options in this case are to either re-create the FaultException in my BLL service, which creates the proper Action, but when it reaches my client, it appears to be coming from the BLL service; the fact that it originates in DAL is lost unless I specify it explicitly, or else add the Action property to the FaultContract attribute on the BLL operation, and specify the Action of the fault generated by the DAL. As to which is a better idea and better practice, that is likely a whole other topic, but I now have an understanding of what is going on, which is what I was after.

Related

How client application comes to know that a particular wcf method throws faultexception or not?

I know a wcf method throws fault exception and client application catches that fault exception. But is there any way to know that whether that wcf method throws fault exception or not at client side ?
When you create a WCF service you could decorate your operation contract with the [FaultContract] attribute:
[ServiceContract]
public interface IService1
{
[OperationContract]
[FaultContract(typeof(MyFaultContract))]
void DoWork();
}
This emits information about this MyFaultContract in the metadata (WSDL) of the service. Then when you create a client proxy (either using the Add Service Reference in VS or directly by the svcutil.exe) this fault contract is known by the client and you can catch exceptions of this type.
So the idea here is to look whether your operation contract is decorated with the [FaultContract] attribute to know which type of fault contracts this operation might throw. If it hasn't any custom FaultContract attributes defined on it it means that on the client you can catch only for the non-generic version of the FaultException.

Is it possible to configure a WCF service client to throw a custom FaultException?

I was wondering if it was possible to configure a WCF service client to use a custom type instead of FaultException when throwing faults. The custom type would inherit from FaultException, but also have some additional details about the error.
The reason I want to use a custom FaultException is so I can store a GUID from the SOAP Header which is otherwise lost.
I know I could manually catch and rethrow any faults my service client returns, but that's flimsy. I have no way of guaranteeing future developers will do the same.
I've thought about subclassing the generated service client class and putting the error handling in there, but that generates a lot of work whenever the target service changes.
So, is it possible to configure a WCF service client to throw a custom FaultException type for Faults?
You can create your own IErrorHandler implementation:
http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler.aspx
Override ProvideFault and then do conversion from regular exceptions (including plain FaultException) to your own custom based FaultException<T>, where T is your own type that you can define to include custom properties.
After that, you have to register your implementation of IErrorHandler as service behavior, either in code or in web/app config.

WCF/WebService: Interoperable exception handling

I understand that WCF will convert an exception into a fault and send it back as a SOAP message, but I was wondering if this is truly interoperable. I guess I'm having a tough time trying to figure out this possible scenario:
Client (Java) calls a WCF Service
(LoginService).
Server checks for proper authorization, user authorization fails.
Server throws an UnauthorizedAccessException.
WCF converts this into a Fault somehow. (* - See Below As Well)
Client has to be able to know how to read this Fault.
I guess I'm just having a tough time understanding how this could still be interoperable because it is expecting Java to know how to translate a SOAP Fault that .NET encodes from an UnauthorizedAccessException.
Also, how does .NET actually convert the exception to a fault, what goes in as the fault code, name, etc. Some of the things seem to be "duh"s like perhaps the Fault Name is "UnauthorizedAccessException", but I'd rather know for sure than guess.
There is no "automatic conversion". WCF will return a fault (I forget which one) when you have an unhandled exception. But since you didn't declare that fault, many, if not most, clients will fail if you return it.
You are meant to define your own faults and to return them instead. Consider:
[DataContract]
public class MySpecialFault
{
public string MyMessage { get; set; }
}
[ServiceContract]
public interface IMyService
{
[FaultContract(typeof (MySpecialFault))]
[OperationContract]
void MyOperation();
}
public class MyService : IMyService
{
public void MyOperation()
{
try
{
// Do something interesting
}
catch (SomeExpectedException ex)
{
throw new FaultException<MySpecialFault>(
new MySpecialFault {MyMessage = String.Format("Sorry, but {0}", ex.Message)});
}
}
}
Any client capable of handling faults will deal with this. The WSDL will define the fault, and they will see a fault with the Detail element containing a serialized version of the MySpecialFault instance that was sent. They'll be able to read all the properties of that instance.
Faults have been part of the SOAP specification since v1.1. They are explained in the SOAP Specification.
It is up to implementations (WCF, Java etc) to ensure that Faults are handled according to the specification.
Since WCF converts FaultExceptions to Faults according to the SOAP specification, FaultExceptions thrown from WCF are interoperable.
SOAP faults are interoperable but .Net exception classes are not good to be used in SOAP faults. Instead define your own DataContract class (e.g. AccessFault) and then use it in a FaultContract.
see http://msdn.microsoft.com/en-us/library/ms733841.aspx
Whenever there is a UnauthorizedAccessException thrown at service boundary convert it to FaultException.
This can be done in several ways like using Microsoft Enterprise Library Exception Handling Block or implementing the IErrorHandler interface.

WCF - Catching faults on the server and returning custom types instead

We are trying to figure out a way to modify WCF service behavior to catch all exceptions and instead of returning faults to the client, it will populate a custom return object with exception data and return that. So far, we haven't had much luck. I found this example: Catching custom faults
However, it doesn't return custom types as we would like it to. What other options are there?
Thanks!
If you want to have an interoperable and "by-the-standard" service, you should always return FaultException<T> SOAP faults from your service to the client.
Since that type takes a generic <T>, you can basically put anything into that type there to report back your errors. That type needs to be decorated with a [DataContract], and its members that need to be passed back with [DataMember] attributes.
[DataContract]
public class MyErrorInfo
{
[DataMember]
public int ErrorCode { get; set; }
[DataMember]
public string ErrorMessage { get; set; }
}
When you catch those execptions on the service side and return a FaultException<MyErrorInfo> (or whatever you'll end up calling your error class), you also need to decorate your operations with a
[FaultContract(typeof(MyErrorInfo))]
[OperationContract]
public SomeType SomeMethodCall(SomeType parameter);
so that your clients will be able to catch the FaultException<MyErrorInfo> and handle it.
I referred to this article in another answer, but it may help you as well..
WCF Exception Handling
the article is Simplifying WCF: Using Exceptions as Faults
I wrote a blog post on this exact topic after we encountered this in our own project. Basically, we chose to return the same object type so we can attach a single listener delegate to all events to globally handle certain errors (like a user losing the permissions to an org.)
I hadn't thought of using FaultException but I will examine how we might do that. This design was WCF Service (.NET 3.5) running inside SharePoint 2007 and consumed by Silverlight 4.

What is the best approach to handle exceptions in WCF service?

I have a WCF service deployed on two or more remote machines and there is a desktop based application that is used by the client to access any wcf service.
The WCF service is connected to SQL server 2005 to read and write data.
This is an intranet scenario in which the client should be on same domain.
Now there can be scenarios where the wcf service throws exceptions:
Invalid URL
WCF service is down
SQL server 2005 is not running
Client is not on the same domain
Authentication fails
Authorization fails
and many other exceptions.
For every exception I have to perform some action or update a status bar, depending on the exception. For example if authorization fails I have to prompt the user to re-enter their credentials.
Please suggest the best design approach to handle this.
You can definitely catch and handle all exceptions that happen on your service class and turn them into a FaultException or FaultException exception.
That way, you won't "fault" (or tear down) the communications channel between your client and server.
Even better approach would be to implement the IErrorHandler interface on your service class that provides a way to globally catch all exceptions as they happen and provide a FaultException instead, that's SOAP compliant.
You can even turn your IErrorHandler into a configurable behavior that can be turned on or off in config.
See these articles and blog posts for more details:
Rory Primrose: Implementing IErrorHandler
Useful WCF behaviors: IErrorHandler
Create a custom fault class that is marked with the DataContract attribute
Mark the method on the service contract interface with FaultContract. Ie. [FaultContract(typeof(CustomFault))]
In your service method, catch any applicable internal exceptions and throw a FaultException<CustomFault>. Alternatively, as marc_s mentioned, you can use IErrorHandler to map the exception to the fault.
Personally, I create a base Fault class that has a Reason property and I extend all custom faults from this class. When I want to throw the fault, I call:
throw Fault.Create<CustomFault>(new CustomFault("Boo hoo"));
It's also worth noting that I version my fault classes (including the common Fault class) along with all my other services. This is only a concern if service versioning is a concern, though.
Here's the basic Fault class (I've removed argument validation for brevity):
[DataContract(Namespace = XmlVersionNamespace.FaultNamespace)]
public abstract class Fault
{
internal FaultReason Reason { get; set; }
protected Fault(string reasonText)
{
Reason = new FaultReason(new FaultReasonText(reasonText, CultureInfo.CurrentUICulture));
}
public override string ToString()
{
return Reason.ToString();
}
internal static FaultException<TDetail> Create<TDetail>(TDetail fault) where TDetail : Fault
{
return new FaultException<TDetail>(fault, fault.Reason);
}
}
You can design the specific Fault Data Contracts for each of the exception scenario in your WCF service so that you can handle the fault/exception at client side respectively.
try
{
// Actions
}
catch (Exception ex)
{
// Log the exception
// Throw Fault Exception back to client
FaultException fe = new FaultException(ex.Message, new FaultCode("Your fault code"));
//throw fault exception back to WCF client
throw fe;
}