views:

130

answers:

7

Working with .NET framework I have a service with a set of methods that can generates several types of exceptions: MyException2, MyExc1, Exception... To provide proper work for all methods, each of them contains following sections:

[WebMethod]
void Method1(...)
{
    try
    {
        ... required functionality
    }
    catch(MyException2 exc)
    {
        ... process exception of MyException2 type
    }
    catch(MyExc1 exc)
    {
        ... process exception of MyExc1 type
    }
    catch(Exception exc)
    {
        ... process exception of Exception type
    }
    ... process and return result if necessary
}

It is very boring to have exactly same stuff in EACH service method (each method has different set of parameters) with exactly same exceptions processing functionality...

Is there any possibility to "group" these catch-sections and use only one line (something similar to C++ macros)? Probably something new in .NET 4.0 is related to this topic?

Thanks.

P.S. Any thoughts are welcome.

+6  A: 

If the exception handling is exactly the same in all of your methods, you could do something like:

void CallService(Action method)
{
    try
    {
        // Execute method
        method();
    }
    catch(MyException2 exc)
    {
        ... process exception of MyException2 type
    }
    catch(MyExc1 exc)
    {   
        ... process exception of MyExc1 type
    }
    catch(Exception exc)
    {
        ... process exception of Exception type
    }
}

Then, you could just rewrite your client code to do:

int i = 3;
string arg = "Foo";
this.CallService( () => this.Method1(i) );
this.CallService( () => this.Method2(arg, 5) );

This allows your Method1 and Method2 methods to be simply:

void Method1(int arg)
{
    // Leave out exception handling here...
    ... required functionality  
    ... process and return result if necessary
}

void Method2(string stringArg, int intArg)
{
    // Leave out exception handling here...
    ... required functionality  
    ... process and return result if necessary
}
Reed Copsey
I had a similar idea, but the problem is that each method has different set of parameters (sorry, I didn't mention that in original question and added specification recently). Here is example of methods signatures: string Method1(string); void Method2(string, int, int), etc...
Budda
@Budda: that doesn't matter - it'll work fine with that, since lambdas can pass in all of the arguments, the way I wrote it.
Reed Copsey
@Budda: I edited my answer to demonstrate :) This works for any number of arguments in the methods...
Reed Copsey
Thanks. But in this case we need additional method for each "MyMethodX", right? I would avoid that... And this can be achieved with anonymous methods, something like this:this.CallService( () => { ... required functionality} ); without separate method definition... Right? :)Thank you again.
Budda
@Budda: Yes, you can avoid the method entirely, if you don't need it. I was just trying to port your examples over. You have a lot of flexibility here...
Reed Copsey
@Budda: You can also use an anonymous method with lambdas.
chilltemp
A: 

I know it's bad practice, but if you have the exact same error handling in each catch statement, when why not just use the last catch statement as a catch all?

This of course assumes all your exceptions inherit from Exception.

Damien Dennehy
-1: ifyou know it's a bad practice, then why recommend it?
John Saunders
I'm not - I'm just curious to know why you would have the exact same error handling in multiple catch statements, as the point of having multiple catches is that you handle your exceptions differently...
Damien Dennehy
I have exactly same handling in order to provide the same error processing for all methods.
Budda
I think you misunderstood the issue. If I understand correctly: Within one of his methods, each catch{} block doesn't have the same handling. What he has is the same set of catch{} blocks and handling across multiple methods
Odrade
You're right, I didn't catch the part in the original question regarding multiple methods. Apologies.
Damien Dennehy
+5  A: 

Why not just factor the code into a helper method to do it for you (you can add whatever new exceptions you need in the future to HandleException as well, which makes it quite scalable)?

try
{
    ... required functionality
}
catch (Exception e)
{
    HandleException(e);
    throw; // only if you need the exception to propagate to caller
}


private void HandleException(Exception e)
{
    if (e is MyException2)
    {
        ... process exception of MyException2 type
    }
    else if (e is MyExc1)
    {
        ... process exception of MyExc1 type
    }
    else
    {
        ... process exception of Exception type
    }
}
dcp
dcp, why do you re-throw exception after call to HandleException(e)?
Budda
This pattern would defiantly violate Microsoft's code analysis rule "Do not catch general exception types" http://msdn.microsoft.com/en-us/library/ms182137(v=VS.90).aspx
chilltemp
@chilltemp - Come on, the do not repeat your self rule has a much higher precedence.
ChaosPandion
@Budda - The rethrow is so the caller can handle the exception. If that's not needed, then the rethrow could be removed, but normally you want to let the exception propagate so the caller knows something failed.
dcp
@chillitemp - I think the idea behind the Microsft rule is that you are better to handle specific exceptions (if you know what exceptions you are expecting) and take the proper action as opposed to just using catch(Exception e). In this case though, we are taking the specific action in the HandleException method. So we are really adhering to the spirit of the rule, we're just doing it a little differently to enable code reuse, which as @ChaosPandion points out, is really of higher precedence.
dcp
Thanks, those methods are highest in WebService... So nobody is interested in propagation here.
Budda
This also re-throws exceptions which have been handled in HandleException.
Odrade
@Odrade - See my previous comment to @Budda. Often times rethrowing is the desired behavior. Just because we've "handled" the exception doesn't necessarily mean we shouldn't let it rethrow to the caller. It depends on the circumstances.
dcp
@ChaosPandion: I've seen this exact pattern used many places throughout the company I work for. It has almost always includes other bad practices like 'throw ex' within the common exception handler. I agree that this rule isn't valid in all cases, but personal experience has led me to distrust common exception handlers. Make a common exception handler for each exception type, not one handler to rule them all. (And, yes I violate this code analysis rule all the time. I just don't promote it as a good pattern.)
chilltemp
@dcp: Why handle the exception if you are going to rethrow 100% of them? It would make more sense to conditionally rethrow the exception if the HandleException method couldn't handle it. Perhaps it should return a bool.
chilltemp
@chilltemp - I usually do it at the class level. I think it's just a matter of using the technique properly. You can do stupid things or abuse any technique. I've used this pattern over and over also and I like it because the error handling logic is centralized.
dcp
@chilltemp, @dcp - As always, think before you break a common rule. Just remember, the biggest leaps in technological development have come from going against the grain.
ChaosPandion
+2  A: 

I'd look closely at what you're doing to "process" these exceptions. There's a good chance that you don't need the catch blocks at all, and that you should be permitting the exceptions to propagate.

John Saunders
Those methods are [WebMethod] of web-service and they should ALWAYS return something meaningful to client. All exception handling sections generate "error" object, that is serialized into XML-format and is sent to client. Your suggestion gave me an idea to optimize error-object generation... it can be implemented with a factory pattern... in the following way: catch (Exception exc) { MyError error = MyError.GenerateErrorObject(exc); ... process(error); }Thanks.
Budda
@Budda: 1) That's nice to know. Say so next time. 2) You should be throwing `SoapException` with the detail set to return a SOAP Fault.
John Saunders
I need to send message in CERTAIN custom format, and SOAP exception doesn't fit :)
Budda
+1  A: 

In a sudden flash of geekiness (and to show what you could but most probably should not and do not want to do): You can make the whole thing more composable and reusable by generating functions on the fly that contain the exception handling logic:

static class ExceptionHandlerExtensionMethods 
{
    // extend to Func<T> as desired
    public static Action Catching<T>(this Action what, Action<T> handler) 
        where T : Exception
    {
        return () =>
        {
             try
             {
                 what();
             }
             catch (T ex)
             {
                 handler(ex);
             }
         };
    }
}

Now you can implement and reuse exception-type specific handler functions somewhere, and compose them into the exception handling of some other method.

To remove the redundancy, you can write a helper function that adds the "typical" exception handler functions to what ever you want to call and call this decorated method instead.

Arne
A: 

Using the CallService method from Reed Copsey:

void DoSomething(object param1, int param2)
{
    this.CallService(() =>
    {
         // work with param1 and param2 here
    }
}

For the cases when you need to return a value, you might have to duplicate CallService to return a type parameter.

T CallService<T>(Func<T> callback) { /* ... */ }
Francis Gagné
+1  A: 

I've done the following in a similar situation. I'll show the technique in two steps...


Step 1. Create a method that provides a specific execution context for other code:

// this static method is responsible for setting up a context for other code
// to run in; specifically, it provides the exception handling "plumbing":
public static void guarded(Action action)
{                      //  ^^^^^^^^^^^^^
    try                //  actual code to be executed
    {
        action();
    }
    catch (SomeExceptionA ea)
    {
        // handle exception...
    }
    catch (SomeExceptionB eb)
    {
        // handle exception...
    }
    // etc.
}

Step 2. Apply this context to any piece of code:

Next, you simply "wrap" this exception handling around the actual code in your methods:

public void MethodA()
{
    guarded(() =>   // <-- wrap the execution handlers around the following code:
    {
        // do something which might throw an exception...
    });
}

public void MethodB()
{
    guarded(() =>
    {
        // do something which might throw an exception...
    });
}

Summary:

The general idea here is to write a function (guarded in the above example) that sets up a specific execution context for other code to run in. (The context in this example is providing exception handling.) The code that is to be executed in this context is provided as a lambda function. You could even adapt the context-creating function so that the code in the lambda function can return a value.

stakx
Same as Reed Copsey suggested. But thank you anyway.
Budda
Oops. Sorry for the almost-duplicate, I somehow managed to overlook his answer. **BUT** note a subtle difference in our two answers: In his answer, the outer function is explicitly wrapped around the actual method _by the method's caller_. I would suggest that there are also cases where it's more appropriate to _let your methods handle their context themselves_. They might know better than the caller what exceptions can/must be handled.
stakx