Catching exceptions with servicestack

2019-02-10 06:45发布

问题:

We have been using ServiceStack for REST based services for a while now and so far it has been amazing.

All of our services have been written as:

public class MyRestService : RestService<RestServiceDto>
{
   public override object OnGet(RestServiceDto request)
   {
   }
}

For each DTO we have Response equivalent object:

public class RestServiceDto 
{
    public ResponseStatus ResponseStatus {get;set;}
}

which handles all the exceptions should they get thrown.

What I noticed is if an exception is thrown in the OnGet() or OnPost() methods, then the http status description contains the name of the exception class where as if I threw a:

new HttpError(HttpStatus.NotFound, "Some Message");

then the http status description contains the text "Some Message".

Since some of the rest services are throwing exceptions and others are throwing new HttpError(), I was wondering if there was a way without changing all my REST services to catch any exceptions and throw a new HttpError()?

So for example, if the OnGet() method throws an exception, then catch it and throw a new HttpError()?

回答1:

Using Old API - inherit a custom base class

As you're using the old API to handle exceptions generically you should provide a Custom Base class and override the HandleException method, e.g:

public class MyRestServiceBase<TRequest> : RestService<TRequest>
{
   public override object HandleException(TRequest request, Exception ex)
   {
       ...
       return new HttpError(..);
   }
}

Then to take advantage of the custom Error handling have all your services inherit your class instead, e.g:

public class MyRestService : MyRestServiceBase<RestServiceDto>
{
   public override object OnGet(RestServiceDto request)
   {    
   }
}

Using New API - use a ServiceRunner

Otherwise if you're using ServiceStack's improved New API then you don't need to have all services inherit a base class, instead you can just tell ServiceStack to use a custom runner in your AppHost by overriding CreateServiceRunner:

public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(
    ActionContext actionContext)
{           
    return new MyServiceRunner<TRequest>(this, actionContext); 
}

Where MyServiceRunner is just a just custom class implementing the custom hooks you're interested in, e.g:

public class MyServiceRunner<T> : ServiceRunner<T> {
    public override object HandleException(IRequestContext requestContext, 
        TRequest request, Exception ex) {
      // Called whenever an exception is thrown in your Services Action
    }
}