3
\$\begingroup\$

I've created a generic try catch I can apply throughout my code so I'm not repeating myself.

private HttpResponseMessage TryCatch(Action action)
{
    return TryCatch(() => { action(); return "ActionToFunc"; });
}

private HttpResponseMessage TryCatch<T>(Func<T> func)
{
    try
    {
        var result = func();

        if (result.ToString() == "ActionToFunc")
        {
            return Request.CreateResponse(HttpStatusCode.OK);
        }

        return Request.CreateResponse(HttpStatusCode.OK, result);
    }
    catch (ArgumentNullException)
    {
        return Request.CreateResponse(HttpStatusCode.NotFound);
    }
    catch (Exception ex)
    {
        return Request.CreateResponse(HttpStatusCode.InternalServerError);
    }
}

I can call it using:

TryCatch(() => myFunction(parameter));

Is there a better way of doing achieving the same result?

\$\endgroup\$

2 Answers 2

3
\$\begingroup\$

Try to avoid using magic values. This one is a hack to avoid writing 2 methods.

private HttpResponseMessage TryCatch(Action action)
{
    return TryCatch(() => { action(); return "ActionToFunc"; });
}

You are better of splitting your methods. Dispatch error handling to its own method ResolveStatusCode to avoid boiler-plate error handling. In addition, perform argument checks. Since your method is private, I would favor Debug.Assert over ArgumentNullException.

    HttpResponseMessage TryCatch(Action operation)
    {
        try
        {
            Debug.Assert(operation != null, "invalid usage of API");
            operation();
            return Request.CreateResponse(HttpStatusCode.OK);
        }
        catch (Exception error)
        {
            return Request.CreateResponse(ResolveStatusCode(error));
        }
    }

    HttpResponseMessage TryCatch<T>(Func<T> func)
    {
        try
        {
            Debug.Assert(func != null, "invalid usage of API");
            var result = func();
            return Request.CreateResponse(HttpStatusCode.OK, result);
        }
        catch (Exception error)
        {
            return Request.CreateResponse(ResolveStatusCode(error));
        }
    }
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for your suggestion. I think you're right, this is definitely the way to go. Thanks for introducing me to Debug.Assert() as well, it's something I haven't seen before and will be looking into. \$\endgroup\$
    – Jack Tyler
    Commented Jun 3, 2019 at 8:41
2
\$\begingroup\$

I want to start off by saying dfhwze is the correct answer.

I just wanted to touch more on the magic string "ActionToFunc". Sometimes, especially with functional programming, you need to convert an Action to a Func<>. I would copy what is already proven and working by borrowing from F# and Rx and create a Unit struct

Here is documentation on F# about Unit https://docs.microsoft.com/en-us/dotnet/fsharp/language-reference/unit-type

and Rx info on Unit https://docs.microsoft.com/en-us/previous-versions/dotnet/reactive-extensions/hh211727(v%3Dvs.103)

Both state Unit Struct Represents void.

And here is the Rx source code for Unit, in case you don't want to add Rx just for a struct.

https://github.com/dotnet/reactive/blob/f71f2d62fcec2eb44ca6eaced3b58b21e0372076/AsyncRx.NET/System.Reactive.Shared/System/Reactive/Unit.cs

Repeat this isn't the case for it but for example instead of magic string would have done

if (result == Unit.Default) // Treat this as a void method
\$\endgroup\$

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.