views:

231

answers:

9

In my services all exposed methods have:

try
{
    // the method core is written here
}
catch(Exception ex)
{
    Log.Append(ex);
}

It's boring and ugly to repeat it over and over again. Is there any way to avoid that? Is there a better way to keep the service working even if exceptions occur and keep sending the exception details to the Log class?

+5  A: 

Try AOP. This is the most widely-used selling point of AOP.

Also, see this discussion here on SO.

Anton Gogolev
wait, the example in the blog post you pointed doesn't remove the `try-catch`. It refactors only the `Log.Append` line, right?
Jader Dias
With Aspect Oriented Programming you approach things differently. Look at PostSharp's intro for an idea - http://www.sharpcrafters.com/postsharp/documentation/getting-started - that way you don't use try/catch etc for logging you would use an attribute. Obviously you would still need try/finally for code cleanup etc. BTW, the postsharp link is an example - am am not saying its the solution that you need.
Paul Kohler
+1  A: 

I once used something like the Template Function Pattern to resolve a problem like this. I had a base class that did something like:

public void Execute()
{
    try
    {
        ExecuteImplementation();
    }
    catch (Exception ex)
    {
        // Log ex
    }
}

public abstract void ExecuteImplementation();

There was one derived class per web service operation. The derived classes each implemented ExecuteImplementation.

The web service operations did:

[WebMethod]
public Result WebOperation(Request request)
{
    WebOperationClass instance = new WebOperationClass(request);
    instance.Execute();
    return instance.Result;
}
John Saunders
Your solution inspired my own, which I posted here as an answer
Jader Dias
+4  A: 

I came up with a semi-solution right now. I can refactor the code:

public TResult ExecuteAndLogOnError(Func<TResult> func)
{
    try
    {
        return func();
    }
    catch(Exception ex)
    {
       // logging ...
    }
}

And then you can call it on each method:

return ExecuteAndLogOnError(() =>
{
    // method core goes here..
});

Which is 4 lines shorter than the original scenario.

Jader Dias
It's quite probable that it will lead to unnecessary closures.
empi
@empi what is a closure?
Jader Dias
@Jader Dias - this question is harder than your initial one ;) http://blogs.msdn.com/ericlippert/archive/2003/09/17/53028.aspx
empi
@empi I read it, but I couldn't imagine one scenario where the code above will cause problems
Jader Dias
@Jader Dias - first of all you will have to remember to execute your methods this way (nothing to do with closures). Now for the closures part - closures can be quite hard to understand. You will have to understand variable lifetime when using closures. It may also lead to some quirks that you don't have to expect e.g. http://blogs.msdn.com/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx. What I'm trying to say is that you're adding complexity that in my opinion is not necessary.
empi
+2  A: 

If all your doing is logging then just log the error at a later stage... No need to log the error early. If you do more than log the error, well then you're gonna need the try..catch anyway. And if you swallow exceptions (IE. just log them and then go on as if nothings happened) then maybe you're doing it wrong...

noocyte
+3  A: 

In such cases I always use centralized error handlers. In WCF it is very easy. Some more details: http://www.haveyougotwoods.com/archive/2009/06/24/creating-a-global-error-handler-in-wcf.aspx

Basically, you just implement the IServiceBehavior interface and then provide your own error handler. That is the best way to do this because you don't have to write any code that handles fatal exceptions (I mean exceptions that you can only log and you don't know what to do about them) in your methods.

empi
+1  A: 

Exception filters would be good for this. Alas, .NET supports them through MSIL, C++/CLI, VB.NET, but not C#.

Ben Voigt
wow, never heard of a MSIL feature missing in C#
Jader Dias
Actually there are quite a few. Non-virtual calls to methods other than the base class would be another example. Parameterless constructors for value types. Generic covariance was available in the runtime a major version before C# picked it up (actually I guess C# support is still in beta).
Ben Voigt
+1  A: 

If all you're doing in your catch is logging the exception, you could maybe just use a custom error page and let ELMAH log all your uncaught exceptions.

Daniel Coffman
I don't use ASP.NET or IIS in this project
Jader Dias
+4  A: 

You could set up a generic error handling method for all uncaught exceptions like so:

AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);

Depending on what went wrong, you may not be able to recover from the error... but this should hopefully give you some idea of what what went wrong. If it gets to the point where your application code hasn't handled the exception gracefully, this method could attempt to reinitialize the service to a known working state.

smencer
A: 

A previous poster brought up AOP (Aspecte-Oriented Programming).

I use PostSharp for basic logging traces/exceptions.

It's quite easy to use and setup.

Check out this link and watch the tutorial.

http://www.sharpcrafters.com/postsharp

--crap it is no longer open source ... anyways you can grab Postsharp1.5 and mess around with it to see if it is something you are interested in it.

I am also in no way affiliated with PostSharp. I'm just a user.

Dave Hanson