Question

I have a ServiceStack REST service and I need to implement custom error handling. I've been able to customize service errors by setting AppHostBase.ServiceExceptionHandler to a custom function.

However, for other types of errors, such as validation errors, this doesn't work. How can I cover all cases?

In other words, I'm trying to achieve two things:

  1. Set my own HTTP status codes for every kind of exception that might pop up, including non-service errors (validation)
  2. Return my own custom error object (not the default ResponseStatus) for every error type

How would I go about achieving this?

Was it helpful?

Solution

The AppHostBase.ServiceExceptionHandler global handler only handles service exceptions. To handle exceptions occurring outside of services you can set the global AppHostBase.ExceptionHandler handler, e.g:

public override void Configure(Container container)
{
    //Handle Exceptions occurring in Services:
    this.ServiceExceptionHandler = (request, exception) => {

        //log your exceptions here
        ...

        //call default exception handler or prepare your own custom response
        return DtoUtils.HandleException(this, request, exception);
    };

    //Handle Unhandled Exceptions occurring outside of Services, 
    //E.g. in Request binding or filters:
    this.ExceptionHandler = (req, res, operationName, ex) => {
         res.Write("Error: {0}: {1}".Fmt(ex.GetType().Name, ex.Message));
         res.EndServiceStackRequest(skipHeaders: true);
    };
}

To create and serialize a DTO to the response stream in the non-service ExceptionHandler you would need to access and use the correct serializer for the request from IAppHost.ContentTypeFilters.

More details about is in the Error Handling wiki page.

OTHER TIPS

I made improvements to @mythz' answer.

public override void Configure(Container container) {
    //Handle Exceptions occurring in Services:

    this.ServiceExceptionHandlers.Add((httpReq, request, exception) = > {
        //log your exceptions here
        ...
        //call default exception handler or prepare your own custom response
        return DtoUtils.CreateErrorResponse(request, exception);
    });

    //Handle Unhandled Exceptions occurring outside of Services
    //E.g. Exceptions during Request binding or in filters:
    this.UncaughtExceptionHandlers.Add((req, res, operationName, ex) = > {
        res.Write("Error: {0}: {1}".Fmt(ex.GetType().Name, ex.Message));

#if !DEBUG
        var message = "An unexpected error occurred."; // Because we don't want to expose our internal information to the outside world.
#else
        var message = ex.Message;
#endif

        res.WriteErrorToResponse(req, req.ContentType, operationName, message, ex, ex.ToStatusCode()); // Because we don't want to return a 200 status code on an unhandled exception.
    });
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top