Skip to content
Demis Bellot edited this page Oct 25, 2016 · 42 revisions

This page has moved to docs.servicestack.net/validation


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 ss-utils.js JavaScript library to trivially bind your response errors to your HTML form fields with a single line of code.


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.

Note: The response DTO must follow the {Request DTO}Response naming convention and has to be in the same namespace as the Request DTO

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 JsonServiceClient(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 {0} does not exist".Fmt(request.Name));
}

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

Validation Feature

For more complex validation and to be able to return multiple validation errors ServiceStack includes the excellent Fluent Validation library by @JeremySkinner - a very clean and DSL-like way to validate request DTOs. Even contextual validation for each HTTP method (GET, POST, ...) is supported.

ServiceStack's Fluent Validation feature is encapsulated in the ValidationFeature plugin which can be registered in your AppHost with:

Plugins.Add(new ValidationFeature());

FluentValidation for request dtos

The example below uses this request dto for validation:

[Route("/users")]
public class User
{
    public string Name { get; set; }
    public string Company { get; set; }
    public int Age { get; set; }
    public int Count { get; set; }
    public string Address { get; set; }
}

The validation rules for this request dto are made with FluentValidation. ServiceStack makes heavy use of [rule sets] (https://github.com/JeremySkinner/FluentValidation/wiki/b.-Creating-a-Validator#rulesets) to provide different validation rules for each HTTP method (GET, POST, PUT...).

Tip: First read the documentation about FluentValidation before you continue reading

public interface IAddressValidator
{
    bool ValidAddress(string address);
}

public class AddressValidator : IAddressValidator
{
    public bool ValidAddress(string address)
    {
	return address != null
	    && address.Length >= 20
	    && address.Length <= 250;
    }
}

public class UserValidator : AbstractValidator<User>
{
    public IAddressValidator AddressValidator { get; set; }
    
    public UserValidator()
    {
        //Validation rules for all requests
        RuleFor(r => r.Name).NotEmpty();
        RuleFor(r => r.Age).GreaterThan(0);
        RuleFor(x => x.Address).Must(x => AddressValidator.ValidAddress(x));

        //Validation rules for GET request
        RuleSet(ApplyTo.Get, () => {
            RuleFor(r => r.Count).GreaterThan(10);
        });

        //Validation rules for POST and PUT request
        RuleSet(ApplyTo.Post | ApplyTo.Put, () => {
            RuleFor(r => r.Company).NotEmpty();
        });
    }
}

Info: ServiceStack adds another extension method named RuleSet which can handle ApplyTo enum flags. This method doesn't exist in the core FluentValidation framework.

Warning: If a validator for a request dto is created, all rules which aren't in any rule set are executed + the rules in the matching rule set. Normally FluentValidation only executes the matching rule set and ignores all other rules (whether they're in a rule set or not) and the rules which don't belong to any rule set are normally only executed, if no rule set-name was given to the validate method of the validator.

Like services registered in the IoC container, validators are also auto-wired, so if there's a public property which can be resolved by the IoC container, the IoC container will inject it. In this case, the IoC container will resolve the property AddressValidator, if an object of the type IAddressValidator was registered.

Tip: You can access the current IRequest in your Custom Validator from base.Request

Register Validators

All validators have to be registered in the IoC container, a convenient way to register all validators which exist in one assembly is to use RegisterValidators(), e.g:

//This method scans the assembly for validators
container.RegisterValidators(typeof(UserValidator).Assembly);

Optionally you can also register each validator individually:

//Add the IAdressValidator which will be injected into the UserValidator
container.Register<IAddressValidator>(new AddressValidator());

Now the service etc can be created and the validation rules are checked every time a request comes in.

If you try now for example to send this request:

POST localhost:50386/validated
{
    "Name": "Max"
} 

You'll get this JSON response:

{
    "ErrorCode": "GreaterThan",
    "Message": "'Age' must be greater than '0'.",
    "Errors": [
        {
            "ErrorCode": "GreaterThan",
            "FieldName": "Age",
            "Message": "'Age' must be greater than '0'."
        },
        {
            "ErrorCode": "NotEmpty",
            "FieldName": "Company",
            "Message": "'Company' should not be empty."
        }
    ]
}

As you can see, the ErrorCode and the FieldName provide an easy way to handle the validation error at the client side. If you want, you can also configure a custom ErrorCode for a validation rule:

RuleFor(x => x.Name).NotEmpty().WithErrorCode("ShouldNotBeEmpty"); 

If the rule fails, the JSON response will look like that:

{
    "ErrorCode": "ShouldNotBeEmpty",
    "FieldName": "Name",
    "Message": "'Name' should not be empty."
}

Use FluentValidation everywhere!

Of course FluentValidation can be used for any other classes (not only request DTOs), too:

public class TestClass
{
    public string Text { get; set; }
    public int Length { get; set; }
}

Now the validator:

public class TestClassValidator : AbstractValidator<TestClass>
{
    public TestClassValidator()
    {
        RuleFor(x => x.Text).NotEmpty();
        RuleFor(x => x.Length).GreaterThan(0);
    }
}

Info: If FluentValidation isn't used for request DTOs, it behaves the same as documented in the Fluent Validation documentation.

Inside some service code you can validate an instance of this class:

public class SomeService : Service
{
    //You should have registered your validator in the IoC container to inject the validator into this property
    public IValidator<TestClass> Validator { get; set; }

    public object Get(Validated request)
    {
        TestClass instance = new TestClass();

        ValidationResult result = this.Validator.Validate(instance);

        if (!result.IsValid)
        {
            //The result will be serialized into a ValidationErrorException and throw this one
            //The errors will be serialized in a clean, human-readable way (as the above JSON example)
            throw result.ToException();
        }

    }
}

Populating the Response DTO Manually

All the error handling methods illustrated above are just sugar coating for serializing exceptions into your Response DTOs ResponseStatus property. You don't have use any of this as you can simply populate the ResponseStatus property yourself, coupled with the HttpResult class you have complete control of your HTTP Response - this gives you the necessary freedom so you are able to define your own Error handling API and helpers if you have an existing validation library that you would like to use instead.



  1. Getting Started

    1. Creating your first project
    2. Create Service from scratch
    3. Your first webservice explained
    4. Example Projects Overview
    5. Learning Resources
  2. Designing APIs

    1. ServiceStack API Design
    2. Designing a REST-ful service with ServiceStack
    3. Simple Customer REST Example
    4. How to design a Message-Based API
    5. Software complexity and role of DTOs
  3. Reference

    1. Order of Operations
    2. The IoC container
    3. Configuration and AppSettings
    4. Metadata page
    5. Rest, SOAP & default endpoints
    6. SOAP support
    7. Routing
    8. Service return types
    9. Customize HTTP Responses
    10. Customize JSON Responses
    11. Plugins
    12. Validation
    13. Error Handling
    14. Security
    15. Debugging
    16. JavaScript Client Library (ss-utils.js)
  4. Clients

    1. Overview
    2. C#/.NET client
      1. .NET Core Clients
    3. Add ServiceStack Reference
      1. C# Add Reference
      2. F# Add Reference
      3. VB.NET Add Reference
      4. Swift Add Reference
      5. Java Add Reference
    4. Silverlight client
    5. JavaScript client
      1. Add TypeScript Reference
    6. Dart Client
    7. MQ Clients
  5. Formats

    1. Overview
    2. JSON/JSV and XML
    3. HTML5 Report Format
    4. CSV Format
    5. MessagePack Format
    6. ProtoBuf Format
  6. View Engines 4. Razor & Markdown Razor

    1. Markdown Razor
  7. Hosts

    1. IIS
    2. Self-hosting
    3. Messaging
    4. Mono
  8. Security

    1. Authentication
    2. Sessions
    3. Restricting Services
    4. Encrypted Messaging
  9. Advanced

    1. Configuration options
    2. Access HTTP specific features in services
    3. Logging
    4. Serialization/deserialization
    5. Request/response filters
    6. Filter attributes
    7. Concurrency Model
    8. Built-in profiling
    9. Form Hijacking Prevention
    10. Auto-Mapping
    11. HTTP Utils
    12. Dump Utils
    13. Virtual File System
    14. Config API
    15. Physical Project Structure
    16. Modularizing Services
    17. MVC Integration
    18. ServiceStack Integration
    19. Embedded Native Desktop Apps
    20. Auto Batched Requests
    21. Versioning
    22. Multitenancy
  10. Caching

  11. Caching Providers

  12. HTTP Caching 1. CacheResponse Attribute 2. Cache Aware Clients

  13. Auto Query

  14. Overview

  15. Why Not OData

  16. AutoQuery RDBMS

  17. AutoQuery Data 1. AutoQuery Memory 2. AutoQuery Service 3. AutoQuery DynamoDB

  18. Server Events

    1. Overview
    2. JavaScript Client
    3. C# Server Events Client
    4. Redis Server Events
  19. Service Gateway

    1. Overview
    2. Service Discovery
  20. Encrypted Messaging

    1. Overview
    2. Encrypted Client
  21. Plugins

    1. Auto Query
    2. Server Sent Events
    3. Swagger API
    4. Postman
    5. Request logger
    6. Sitemaps
    7. Cancellable Requests
    8. CorsFeature
  22. Tests

    1. Testing
    2. HowTo write unit/integration tests
  23. ServiceStackVS

    1. Install ServiceStackVS
    2. Add ServiceStack Reference
    3. TypeScript React Template
    4. React, Redux Chat App
    5. AngularJS App Template
    6. React Desktop Apps
  24. Other Languages

    1. FSharp
      1. Add ServiceStack Reference
    2. VB.NET
      1. Add ServiceStack Reference
    3. Swift
    4. Swift Add Reference
    5. Java
      1. Add ServiceStack Reference
      2. Android Studio & IntelliJ
      3. Eclipse
  25. Amazon Web Services

  26. ServiceStack.Aws

  27. PocoDynamo

  28. AWS Live Demos

  29. Getting Started with AWS

  30. Deployment

    1. Deploy Multiple Sites to single AWS Instance
      1. Simple Deployments to AWS with WebDeploy
    2. Advanced Deployments with OctopusDeploy
  31. Install 3rd Party Products

    1. Redis on Windows
    2. RabbitMQ on Windows
  32. Use Cases

    1. Single Page Apps
    2. HTML, CSS and JS Minifiers
    3. Azure
    4. Connecting to Azure Redis via SSL
    5. Logging
    6. Bundling and Minification
    7. NHibernate
  33. Performance

    1. Real world performance
  34. Other Products

    1. ServiceStack.Redis
    2. ServiceStack.OrmLite
    3. ServiceStack.Text
  35. Future

    1. Roadmap
Clone this wiki locally