Validation and Error Handling

As validation and error handling is an essential part of developing services, ServiceStack provides a rich array of error handling options that work intuitively out-of-the-box.

Optimized for developer happiness ServiceStack allows you to idiomatically throw C# exceptions directly in your services and trivially consume them on the client with minimal effort, intuitively and conventionally - allowing the opportunity to inject generic error handling routines to handle errors for all your web services.

As a bonus the most appropriate HTTP Status code is returned based upon the C# Exception type.

Typed, Structured Exceptions end-to-end

The error handling support works end-to-end where all errors get auto-serialized into your Response DTO and re-hydrated into a C# Exception on ServiceStack's generic Service Clients. This allows you to idiomatically treat errors like normal C# Exceptions - providing easy access to rich, structured error messages in your clients.

JavaScript support included

To make it trivial to consume errors in JavaScript, you can use the lightweight and embedded dep-free @servicestack/client form binding library or the ss-utils.js jQuery library to trivially bind your response errors to your HTML form fields with a single line of code.

How it works

All Error handling and validation options described below are treated in the same way - serialized into the ResponseStatus property of your Response DTO making it possible for your clients applications to generically treat all Web Service Errors in the same way.

public class Hello : IReturn<HelloResponse> {}

//Follows naming convention and is in the same namespace as 'Hello'
public class HelloResponse 
{
    public ResponseStatus ResponseStatus { get; set; } //Exception gets serialized here
}

If now an exception occurs in the service implementation, the exception is serialized.

Example JSON output:

{
    "ResponseStatus": {
         "ErrorCode": "NotSupportedException",
         "Message": "..."
    }
}

It's up to the client how to handle this service error.

Throw a C# Exception

The easiest way to generate an Error in ServiceStack is to simply throw a C# Exception:

public object Post(User request) 
{
	if (string.IsNullOrEmpty(request.Name))
		throw new ArgumentNullException("Name");
}

By Default C# Exceptions:

  • Inheriting from ArgumentException are returned as a HTTP StatusCode of 400 BadRequest
  • NotImplementedException is returned as a 405 MethodNotAllowed
  • Other normal C# Exceptions are returned as 500 InternalServerError

All Exceptions gets injected into the ResponseStatus property of your Response DTO that is serialized into your ServiceClient's preferred Content-Type making error handling transparent regardless of your preferred format - i.e. the same C# Error handling code can be used for all ServiceClients.

try 
{
    var client = new JsonApiClient(BaseUri);
    var response = client.Send<UserResponse>(new User());
} 
catch (WebServiceException webEx) 
{
    /*
      webEx.StatusCode  = 400
      webEx.ErrorCode   = ArgumentNullException
      webEx.Message     = Value cannot be null. Parameter name: Name
      webEx.StackTrace  = (your Server Exception StackTrace - if DebugMode is enabled)
      webEx.ResponseDto = (your populated Response DTO)
      webEx.ResponseStatus   = (your populated Response Status DTO)
      webEx.GetFieldErrors() = (individual errors for each field if any)
    */
}

Enabling StackTraces

By default display StackTraces in your Response DTOs are disabled, but they're a good to have for development, which you can enable with:

SetConfig(new HostConfig { DebugMode = true });

Customized Error Messages

If you want even finer grained control of your HTTP errors you can either throw or return a HttpError letting you customize the Http Headers and Status Code and HTTP Response body to get exactly what you want on the wire:

public object Get(User request) {
       throw HttpError.NotFound($"User {request.Name} does not exist");
}

the above is a short-hand for new HttpError(HttpStatusCode.NotFound, $"User {request.Name} does not exist") which returns a 404 NotFound StatusCode on the wire.

Validation Feature