Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom exception handling in ServiceStack REST service

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?

like image 516
Alex G. Avatar asked Mar 24 '13 21:03

Alex G.


2 Answers

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.

like image 57
mythz Avatar answered Nov 17 '22 17:11

mythz


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.
    });
}
like image 34
Jim G. Avatar answered Nov 17 '22 19:11

Jim G.