Whenever you're doing WCF calls you must expect Exceptions. (see Pedram Rezaei's blog)
To handle this I have made some generic functionality in order to not copy the ExceptionHandling functionality around.
First of all I make a proxy using SVCUTIL (since I use Visual Studio 2005).
Then I make a wrapper class for the service, this is the class I will use as a service in my code. By doing this I am more resilient to change since I don't know the proxy.
The service wrapper assigns output variables that is uses later in the call to the proxy.
The ServiceCaller is then called, the ServiceCaller wraps a call back to the ServiceWrapper with the ExceptionHandling code.
The service wrapper should implement the IService interface:
public interface IService
{
void Execute();
}
This Execute method is used for the Exception wrapper class I have made called ServiceCaller.
This ServiceCaller handles Exceptions using the P&P ExceptionHandling block. It is important to note that the exception should always be rethrown, the reThrow bool is only there to comply with the way we use the ExceptionHandling applicationBlock elsewhere.
The WCF policy whould log the Exception.
The ServiceCaller looks like this:
public class ServiceCaller
{
public static void Execute(IService theService)
{
Log.Debug("calling ServiceCaller.Execute on " + theService.GetType().FullName, typeof(ServiceCaller));
try
{
theService.Execute();
}
//State of the proxy and channels
catch (ObjectDisposedException ex)
{
bool reThrow = ExceptionPolicy.HandleException(ex, "WCF Policy");
if (reThrow)
{
throw;
}
return;
}
catch (InvalidOperationException ex)
{
bool reThrow = ExceptionPolicy.HandleException(ex, "WCF Policy");
if (reThrow)
{
throw;
}
return;
}
//Business Exceptions
catch (FaultException ex)
{
bool reThrow = ExceptionPolicy.HandleException(ex, "WCF Policy");
if (reThrow)
{
throw;
}
return;
}
catch (TimeoutException ex)
{
bool reThrow = ExceptionPolicy.HandleException(ex, "WCF Policy");
if (reThrow)
{
throw;
}
return;
}
catch (EndpointNotFoundException ex)
{
bool reThrow = ExceptionPolicy.HandleException(ex, "WCF Policy");
if (reThrow)
{
throw;
}
return;
}
//Trying to use the proxy after the underlying channel has faulted
catch (CommunicationObjectFaultedException ex)
{
bool reThrow = ExceptionPolicy.HandleException(ex, "WCF Policy");
if (reThrow)
{
throw;
}
return;
}
//Typically when client and server binding are not compatible
catch (ProtocolException ex)
{
bool reThrow = ExceptionPolicy.HandleException(ex, "WCF Policy");
if (reThrow)
{
throw;
}
return;
}
//Problem evaluation the security settings of the message
catch (MessageSecurityException ex)
{
bool reThrow = ExceptionPolicy.HandleException(ex, "WCF Policy");
if (reThrow)
{
throw;
}
return;
}
//Network avaliability, Wrong Address, Host process not running etc.
catch (CommunicationException ex)
{
bool reThrow = ExceptionPolicy.HandleException(ex, "WCF Policy");
if (reThrow)
{
throw;
}
return;
}
}
}
Now if I have a simple service that gets the type of a message in a message store, Ie. when using the Saga Pattern, I will implement it like this, please note how no ExceptionHandling is in this code, since it is in the ServiceCaller :
public class GetMessageTypeService : IGetMessageTypeService, IService
{
private string _id;
private MessageTypeEnum messageType;
public static IGetMessageTypeService FactoryMethod()
{
return new GetMessageTypeService();
}
public MessageTypeEnum GetMessageType(string id)
{
_id = id;
ServiceCaller.Execute(this);
return messageType;
}
void IService.Execute()
{
using (execute_pptClient target = new execute_pptClient("conig"))
{
InputParameters inp = GetInputParameter();
OutputParameters outp = target.execute(inp);
if(outp.O_TYPEID == 1)
{
messageType = MessageTypeEnum.Loenmodtager;
}
else
{
messageType = MessageTypeEnum.Selvstaendig;
}
}
}
private InputParameters GetInputParameter()
{
InputParameters inp = new InputParameters();
decimal decMessageID;
decimal.TryParse(_id, out decMessageID);
inp.I_ID = decMessageID;
inp.I_IDSpecified = true;
return inp;
}
}