Search code examples
c#.netwcfexceptionwcf-faults

How to return standard message on exception/fault in WCF


In our application all data contract have one parent - OperationResponse and this OperationResponse contains enum (enum type OperationState in property Result) which represents calling result (Ok, InvalidParams, Error).

How can I overwrite WCF behavior after exception - not return Fault state, but return classic message, OperationResponse in my case, but with property Result = OperationState.Error?

Edit: I think, I'm on right way, I need to implement IErrorHandler, but now I'm lost, because I don't know how to set error message into outgoing fault message...

public bool HandleError(Exception error)
{
    // log error
    return true; // we catch error and provide our custom message.
}

public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
    // create result message
    var message = new OperationResponse
    {
        Result = OperationState.Error
    };

    // ok how to return message into ref fault?
}

Edit2: It seems like it's unbreakable problem without solution... I only found same questions without solution like this thread... :(


Solution

  • I'm not sure this is exactly what you are looking for, but it is a fairly manageable way to handle errors from WCF (and probably other systems/contexts).

    Here we create a generic ServiceResponse<T>, which can contain any type of response in the property Data, and status information in Succeeded and StatusMessage.

    Use the CreateServiceResponse() to sort of wrap which ever method you want to call inside this object. This way, you can return a ServiceResponse with Data set to the result from that method. There is an example of usage at the bottom.

    Perhaps you can adjust this to return an instance of your OperationResponse with an OperationState instead of the Succeeded property used here?

    public class ServiceResponse<T>
    {
        public ServiceResponse()
        {
            // Initial default values:
            Data = default(T);
            Succeeded = true;
            StatusMessage = string.Empty;
        }
    
        // Indicates whether the attempted operation was completed successfully. 
        [DataMember]
        public bool Succeeded { get; set; }
    
        // Error messages if an operation fails.
        [DataMember]
        public string StatusMessage { get; set; }
    
        // The main results from any service-call.        
        [DataMember]
        public T Data { get; set; }
    
        [DataMember]
        public String InnerExceptionMessage { get; set; }
    
        public static ServiceResponse<T> CreateServiceResponse(Func<T> responseFunc)
        {
            var response = new ServiceResponse<T>();
    
            try
            {
                response.Data = responseFunc.Invoke();
            }
            catch (Exception ex)
            {
                response = HandleException(responseFunc, ex);
            }
    
            return response;
        }
    
        private static ServiceResponse<T> HandleException(Func<T> responseFunc, Exception ex)
        {
            // Handle any exceptions here, and return a ServiceResponse with 
            // Succeeded = false, and the appropriate messages, etc.
        }
    }
    

    Example of usage (assuming GetClients() will return an IEnumerable):

    var response = ServiceResponse<IEnumerable<Client>>
                       .CreateServiceResponse(() => GetClients(clientGroupId));