Preventing internal exceptions reaching the client

I’d like to stop internal exceptions from reaching the client. For example if an ApplicationException is thrown deep in the call stack it doesn’t make sense to return that to the client.

One approach I’ve been trying out is is to only return exceptions that are thrown from a Service, like this:

ServiceExceptionHandlers.Add((httpReq, request, exception) =>
{
    if (exception.TargetSite == null || !exception.TargetSite.DeclaringType.HasInterface(typeof(IService)))
        return new HttpError(HttpStatusCode.InternalServerError)
        {
            StatusDescription = "ServerError",
            Response = new ErrorResponse
            {
                ResponseStatus = new ResponseStatus("ServerError", "Unexpected error. Sorry!")
            }
        };

    return null;
});

Alternatively I’ve considered creating my own custom exception hierarchy where all exceptions that should be returned to the client are a ServiceError. Other exception types will be hidden and an HttpError will be thrown instead, as above.

Has anyone used either of these approaches or something else to achieve the same result?

Another area where you can customize errors is by overriding AppHost.OnExceptionTypeFilter() where you can customize how the ResponseStatus is populated based on the type of the Exception.

Personally I’d recommend having all logic tied to the Exception Type and not where it’s thrown, otherwise it can get very unpredictable where behavior gets changed by simple and innocent refactoring.

Thanks for your reply, Demis. The TargetSite method does feel like bad magic. I’m just trying to find a method where I can still throw the natural BCL exception.

My latest thought is to use an exception extension method AsError(). This will return a new wrapper ServiceException, which acts as a container for the exception that will be sent back to the client. I’ll then filter exceptions in the handler as described before. So I’ll use it like this.

throw new ArgumentException("Name is invalid").AsError();

With ReturnsInnerException = true the original exception is serialized over the wire.