10

I have a WCF service which logs any exceptions and then throws them as FaultExceptions.

I am doing a lot of repetition e.g. in each service method.

try { 
   // do some work

}
catch(Exception ex)
{
  Logger.log(ex);

  // actually will be Fault Exception but you get the idea.
  throw ex;
}

I am looking for a more elegant way to do this as I am cutting and pasting the try/catch throughout each service.

Is there a design pattern /C# trick that could be used to make this more elegant?

6
  • 16
    Note that "throw ex;" loses the original call stack, whereas "throw;" does not. Commented Mar 4, 2013 at 14:04
  • 1
    Is the body of the try catch the same as well? Commented Mar 4, 2013 at 14:06
  • 1
    You are pretty much looking at Aspect Orientated Programming here - msdn.microsoft.com/en-us/library/aa288717%28v=vs.71%29.aspx. Many of the third party solutions like PostSharp have Exception Handling aspects that do exactly this. Another (worse) solution is to catch all exceptions at the Application Level (like AppDomain_UnhandledException, for example) rather than having local try catch blocks. I say worse because it effectively ties you in to no local exception handling, or littering your code with try/catch(throw) Commented Mar 4, 2013 at 14:07
  • Not really more elegant, but if you just want to write less yourself, you can always use Code Snippets. Commented Mar 4, 2013 at 14:11
  • Here's a link to the PostSharp AOP example - postsharp.net/blog/post/…. Other AOP frameworks include AfterThought and CCISharp. Commented Mar 4, 2013 at 14:13

9 Answers 9

9

You're talking about AOP - Aspect Oriented Programming

Here's how I do it by passing the "work" as a lambda:

public partial static class Aspect
{
  public static T HandleFaultException<T>( Func<T> fn )
  {
    try
    { 
      return fn();
    }
    catch( FaultException ex )
    {
      Logger.log(ex);
      throw;
    }
  }
}

Then to use it:

return Aspect.HandleFaultException( () =>
  {
    // call WCF
  }
);

There are other ways to achieve the same goal, and even some commercial products, but I find this way to be the most explicit and flexible.

For example, you can write an aspect that creates and disposes the client for you:

public partial static class Aspect
{
  public static T CallClient<T>( Func<Client, T> fn )
  {
    using ( var client = ... create client ... )
    {
      return fn( client );
    }
  }
}

and so:

return Aspect.CallClient( client =>
  {
    return client.Method( ... );
  }
);

And then, you can wrap all the aspects you normally want to apply and create one master aspect.

Sign up to request clarification or add additional context in comments.

Comments

5

We have a similar problem in one of our WCF services, which I've solved by using a helper delegate:

public static void ErrorHandlingWrapper(Action DoWork)
{
    try { 
        DoWork();
    }
    catch(Exception ex)
    {
        Logger.log(ex);

        // actually will be Fault Exception but you get the idea.
        throw;
    }
}

Usage:

public void MyMethod1()
{
    ErrorHandlingWrapper(() => {
        // do work
    });
}

public void MyMethod2()
{
    ErrorHandlingWrapper(() => {
        // do work
    });
}

You still have to repeat the wrapper, but that's a lot less code and you can modify the logic in the try..catch in one place.

Comments

3

For WCF specific, you might look into adding own ErrorHandler. This allows you to "inject" your own code to be executed each time any method throws an exception.

You can set it up like this:

serviceHost.Description.Behaviors.Add(new ErrorHandlerBehavior()); //Add your own ErrorHandlerBehaviour

public class ErrorHandlerBehavior : IErrorHandler, IServiceBehavior
{
    private static readonly Logger log = LogManager.GetCurrentClassLogger();

    public bool HandleError(Exception error)
    {
        if (error is CommunicationException)
        {
            log.Info("Wcf has encountered communication exception.");
        }
        else
        {
            // Log
        }

        return true;
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        //Here you can convert any exception to FaultException like this:
        if (error is FaultException)
            return;

        var faultExc = new FaultException(error.Message);
        var faultMessage = faultExc.CreateMessageFault();

        fault = Message.CreateMessage(version, faultMessage, faultExc.Action);
    }

    public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, 
        BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
        foreach (ChannelDispatcherBase channelDispatcher in serviceHostBase.ChannelDispatchers)
        {
            var channelDisp = channelDispatcher as ChannelDispatcher;

            if (channelDisp != null)
                channelDisp.ErrorHandlers.Add(this);
        }
    }

    public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
    {
    }
}

This also allows you to throw all kinds of exceptions and converting them to Fault Exceptions, which are properly handled by WCF later on, without modifying your business layer or applying try/catch code and converting them there.

Comments

1

Template method pattern is doing just this and you can easily implement it without inheritence using C#'s delegates (or lambdas).

Comments

1

You may want to try AspectF (not mine): http://www.codeproject.com/Articles/42474/AspectF-Fluent-Way-to-Add-Aspects-for-Cleaner-Main. It's by Omar Al-Zabir... creator of Dropthings framework, amongst other things. Hope this helps you.

Comments

0

If you simply throw, so propagate exception on top of the calling stack, you can avoid of handling it on every deep level, just catch it on top most (possible) level and log. Remember that Exception object contains stack-trace too.

If you, by the way, need catching, on every level, remember use throw, so call stack will not be affected, instead in a way you use it, it will.

Comments

0

You could also try to subscribe to the Application_Error event in your global.asax file.

For desktop applications there is an UnhandledException event in the AppDomain.

Comments

0

Generally speaking, you could write some exception handlers that does the redundant job for you:

public abstract class ExceptionHandler
{
    /// Returns true if the exception is handled; otherwise returns false.
    public abstract bool Handle(Exception ex);

    protected void Log(Exception ex)
    {
        // Log exception here
    }
}

public class FileExceptionHandler : ExceptionHandler
{
    public override bool Handle(Exception ex)
    {
        this.Log(ex);

        // Tries to handle exceptions gracefully
        if (ex is UnauthorizedAccessException)
        {
            // Add some logic here (for example encapsulate the exception)
            // ...
            return true;
        }
        else if (ex is IOException)
        {
            // Another logic here
            // ...
            return true;
        }

        // Did not handled the exception...
        return false;
    }
}

public class Program
{
    private static void Main(string[] args)
    {
        try
        {
            // File manipulation
            throw new IOException();
        }
        catch (Exception ex)
        {
            if (!new FileExceptionHandler().Handle(ex))
            {
                // Exception not handled, so throw exception
                throw;
            }
        }

        Console.WriteLine("end");
    }
}

Comments

0

If your question is about how to make your current pattern faster for you to work with you can repeat that boiler plate code by creating a Snippet

<CodeSnippets
    xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>
                trylog
            </Title>
            <Shortcut>
                trylog
            </Shortcut>
        </Header>
        <Snippet>
            <Code Language="CSharp">
                <![CDATA[try { 
   // do some work

}
catch(Exception ex)
{
  Logger.log(ex);

  // actually will be Fault Exception but you get the idea.
  throw ex;
}]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.