left-icon

ServiceStack Succinctly®
by Zoran Maksimovic

Previous
Chapter

of
A
A
A

CHAPTER 2

ServiceStack Basics

ServiceStack Basics


In this chapter, we will go through various concepts and background information about ServiceStack including routing, dependency injection, content negotiation, and validation and error handling.

Application Host

The base entry point for ServiceStack is the AppHost (application host). The concept of the application host is to define a central point for configuring and wiring the request to the service. There can be only one application host per application.

In general, a ServiceStack service can be hosted on Internet Information Services (IIS) as a console application, Windows Service, or mixed with an ASP.NET or ASP.NET MVC application.

Web applications will implement the AppHostBase class while the console and Windows Service applications will implement AppHostHttpListenerBase.

In a web application, the application host has to be started only once when the application starts. This can be done in the Global.asax.cs file by calling the Init method in the Application_Start method. The following code shows the minimum that has to be configured.

public class Global : HttpApplication

{

    protected void Application_Start(object sender, EventArgs e)

    {

        new ServiceAppHost().Init();

    }

}

public class ServiceAppHost : AppHostBase

{

    public ServiceAppHost()

        : base("Order Management"typeof (ServiceAppHost).Assembly)

    {

    }

    public override void Configure(Container container)

    {

    }

}

To configure a console application, the style is practically the same. There is no difference apart from inheriting from a different base class and starting the application in the Main() method rather than in the Global.asax.cs file.

public class ServiceAppHost : AppHostHttpListenerBase 

{

    public ServiceAppHost() :

        base("Order Management System"typeof (ServiceAppHost).Assembly)

    {

    }

   

    public override void Configure(Container container) 

    {           

    }

}

static void Main()

{

    ServiceAppHost  appHost = new ServiceAppHost();

    appHost.Init();

    appHost.Start("http://*:80/");

    Console.Read();

}

Service

Historically, there are several ways in which the web service can be created. Interfaces used in earlier versions of ServiceStack used IRestService and IService<T>. However, currently the recommended way is to use ServiceStack.ServiceInterface.Service, which is the approach used in this book.

public class OrderService : ServiceStack.ServiceInterface.Service { }

As shown in the following code, the Service base class implements and exposes several very useful methods and properties such as Request and Response, which are the two most used objects in the service and give a great deal of manipulation and inspection possibilities.

public class Service : IService, IRequiresRequestContext, IServiceBase, IResolver, IDisposable

{

    public virtual IResolver GetResolver();

    public virtual IAppHost GetAppHost();

    public virtual Service SetResolver(IResolver resolver);

    public virtual T TryResolve<T>();

    public virtual T ResolveService<T>();

    protected virtual TUserSession SessionAs<TUserSession>();

    public virtual void PublishMessage<T>(T message);

    public IRequestContext RequestContext { get; set; }

    protected virtual IHttpRequest Request { get; }

    protected virtual IHttpResponse Response { get; }

    public virtual ICacheClient Cache { get; }

    public virtual IDbConnection Db { get; }

    public virtual IRedisClient Redis { get; }

    public virtual IMessageProducer MessageProducer { get; }

    public virtual ISessionFactory SessionFactory { get; }

    public virtual ISession Session { get; }

}

Request

Request implements the .NET built-in IHttpRequest interface and therefore exposes all that we might need to know about the current request. Among the other things to note is the ability to inspect Headers, QueryString, and the current HttpMethod.

Imagine the following HTTP request.

GET http://<servername>/orders?page=1

Accept: application/json

In the service, we can easily retrieve all of the information.

public class OrderService : ServiceStack.ServiceInterface.Service

{

    public object Get(GetOrdersRequest request)

    {

        //value = 1

        var pageQueryStringValue = this.Request.QueryString["page"];

        //value = application/json

        var acceptHeaderValue = this.Request.Headers["Accept"];

        //value = GET

        var httpMethod = this.Request.HttpMethod;

        return null;

    }

}

Response

Response represents the object that the client will eventually receive. Among others, one of the most useful methods exposed by the Response object is the AddHeader method, which manipulates the headers returned to the client. Let’s look at an example of the AddHeader usage.

public class OrderService : ServiceStack.ServiceInterface.Service

{

    public object Get(GetOrdersRequest request)

    {

        this.Response.AddHeader("Location", "http://<servername>/orders");

        return new HttpResult {StatusCode = HttpStatusCode.OK};   

    }

}

The following code shows the Result returned to the client.

HTTP/1.1 200 OK

Cache-Control: private

Content-Type: application/json

Location: http://<servername>/orders

Date: Sun, 28 Jul 2013 22:45:42 GMT

Web Service Method Return Types

A web service method can return one of the following:

  • Response DTO object serialized to the response type (JSON, XML, PNG).
  • Any basic .NET value.
  • HttpResult: Used whenever full control of what client recieves is needed.
  • HttpError: Used to return the error message to the client.
  • CompressedResult (IHttpResult) for a customized HTTP response.

The following two methods both produce the same result.

public class OrderService : ServiceStack.ServiceInterface.Service

{

    public List<GetOrderResponse> Get(GetOrdersRequest request)

    {

        return new List<GetOrderResponse>();

    }

    public HttpResult Get(GetOrdersRequest request)

    {

        return new HttpResult(response: new List<GetOrderResponse>(),

                              contentType: "application/json",

                              statusCode: HttpStatusCode.OK);

    }

}

REST HTTP Methods

The ServiceStack framework virtually supports all of the available HTTP methods. The web service method to be executed will be determined at run time by combining the routes and requested HTTP method. ServiceStack will execute a method of the service that corresponds to the actual HTTP method name. The HTTP verb GET will be executed by Get(), POST will be executed by Post(), and so on.

The following table contains some reminders about the basic HTTP verbs, what they do, and when they are used.

  1. HTTP verbs

GET

  • Retrieves a resource.
  • It is safe (guaranteed not to cause side effects), idempotent,[5] and cacheable.
  • Should never change the state of a resource.

POST

  • Creates a new resource.
  • Unsafe; the effect of this verb is not specifically defined by HTTP.
  • Not idempotent.

PUT

  • Updates an existing resource.
  • Can be used to create a new resource when client knows the URI.
  • Can be called n-number of times and always produces the same effect (idempotent).

DELETE

  • Removes an existing resource.
  • Can be called n-number of times and always produces the same effect (idempotent).

PATCH

  • Not safe, not idempotent.
  • Like PUT, but allows full and partial updates of a resource.

The service can have the same HTTP verb implemented multiple times, but the input parameters should be different as with any other normal method overload.

public class OrderService : ServiceStack.ServiceInterface.Service

{

    public object Get     (SomeRequest request) {...}

    public object Get     (SomeRequest2 request) {...}

    public object Post    (SomePostRequest request) {...}

    public object Post    (SomePostRequest2 request) {...}

}

Content Negotiation

If not specified otherwise, ServiceStack offers mainly three ways of negotiating the content type of the resource:

  • The HTTP Accept header.
  • The format query string parameter.
  • The file extension (e.g., http://<servername>/orders.json).

Use of the HTTP Accept header is considered by many to be a recommended and more elegant way of negotioating the content type, and it is the HTTP standard. However, it’s a hot topic and there is debate about whether to pass the format instructions directly in the URI. I think that it is good to have them both, as both have their pros and cons.

Since you should already be familiar with how to use the HTTP Accept[6] header, we won’t go into details. The following table shows the options available in ServiceStack.

  1. Content negotiation in ServiceStack

Query String Style

File Extension Style

Accept Header

…/orders?format=json

…/orders.json

Accept: application/json

…/orders?format=xml

…/orders.xml

Accept: application/xml

…/orders?format=jsv

…/orders.jsv

Accept: application/jsv

…/orders?format=csv

…/orders.csv

Accept: application/csv

Tip: It’s possible to disable the file extension style by setting   Config.AllowRouteContentTypeExtensions = false in the AppHost instance.

There are different ways of defining the response content type:

  • Forcing the content type for every request to JSON by configuring the application host.

public class ServiceAppHost : AppHostBase

{

    public ServiceAppHost()

        : base("Order Management", typeof(ServiceAppHost).Assembly)

    {

        base.Config.DefaultContentType = ContentType.Json;

    }

}

  • Specifying the content type at the service method’s level, either by using an AddHeader filter or by specifying the ContentType.

[AddHeader(ContentType = ContentType.Json)]

public object Get(GetOrdersRequest request) { /*..*/}

Or, alternatively:

public object Get(GetOrdersRequest request)

{

    base.Response.ContentType = ContentType.Json;

    return /*..*/

}

  • Returning a decorated response via HttpResult.

public object Get(GetOrdersRequest request)

{

    return new HttpResult(responseDTO, ContentType.Json);
}

Routing

Routing is the process of selecting paths along which to send a request. To determine which action to perform for a request, ServiceStack has to keep the list of routes and this has to be instructed specifically when the application starts. There are several ways in which the route can be registered:

  • Using a default route.
  • Creating a custom route by using RouteAttribute or Fluent API.
  • Dynamic paths.
  • Autoregistered paths.

Default Routes

By default, for every Request DTO, ServiceStack will create a default route in the following form:

 /api?/[xml|json|html|jsv|csv]/[reply|oneway]/[servicename]

Let’s suppose we want to support a custom route, http://<servername>/orders, and we expose a Request DTO called GetOrders. In this case, without specifying any route, ServiceStack will create http://<servername>/xml/reply/GetOrders automatically.

Custom Routes

A route can be declared as a class attribute directly at the Request DTO level or in the AppHostBase by using the Fluent API. The route has an option to define one or more HTTP verbs.

Route Attribute

By using the RouteAttribute, a route can be declared directly at the Request DTO object.

[Route("/orders""GET POST", Notes="…", Summary="…")]

public class GetOrders { }

Fluent API

Instead of using the RouteAttribute, the same can be achieved by defining the route in the application host declaration.

public class ServiceAppHost : AppHostBase

{

    public ServiceAppHost()

        : base("Order Management", typeof(ServiceAppHost).Assembly)

    {

        Routes

            .Add<GetOrders>("/orders""GET")

            .Add<CreateOrder>("/orders""POST")

            .Add<GetOrder>("/orders/{Id}""GET")

            .Add<UpdateOrder>("/orders/{Id}""PUT")

            .Add<DeleteOrder>("/orders/{Id}""DELETE")

    }

}

Dynamic Paths

ServiceStack’s routing mechanism offers a way to dynamically bind the parameters sent in the URL and to deserialize the object once it reaches the service. In the following code example, we can see that in the route there is an {Id} declaration. At run time, the value sent as {Id} will be deserialized as the GetOrder.Id property.

[Route("/orders/{Id}""GET")]

public class GetOrder

{

    public string Id { getset; }

}

Autoregistered Paths

By using the Routes.AddFromAssembly(typeof(OrderService).Assembly) method, we can automatically map and define all routes.

using ServiceStack.ServiceInterface;

//Request DTO (notice there is no route defined as the Attribute!)

public class GetOrderRequest

{

    public string Id { getset; }

}

// Service

public class OrderService : ServiceStack.ServiceInterface.Service

{   

    public List<OrderResponse> Get(GetOrdersRequest request) { … }

    public object Post(CreateOrder request) { … }

}

// Autoregistering the routes in the application host.

public class ServiceAppHost : AppHostBase

{

    public ServiceAppHost (): base("Order Management",

        typeof(OrderService).Assembly)

    {

        Routes.AddFromAssembly(typeof (OrderService).Assembly);

    }

}

By using reflection, ServiceStack will check the OrderService, determine the request’s parameter type, and autogenerate the route.

For the previous code example, the route generated will be /GetOrders (GET) and /CreateOrder (PUT).

Route Wildcards

There is a way to define a wildcard in the route; this is especially useful when the route becomes too complex.

The following is an example with a route that uses a wildcard.

Routes.Add("/orders/{CreationDate}//{Others*}", "GET");

In this case, the request would be /orders/2012-11-12/SomeOther/InfoGoes/Here.

This will be translated and deserialized as follows.

CreationDate = 2012-11-12; Others = “SomeOther/InfoGoes/Here”

So, the Others keyword will be taken as it is, and it can then be further processed in the application code.

Where to Place the Route Declaration

My personal preference is to use the AppHost as the only place where all the paths should be declared. While there is nothing wrong with using the the RouteAttribute, I like to have all of the routes declared together in one place.

If the Request and Response DTOs POCO objects are placed in one assembly, it can be distributed without any external dependency to the clients. If using the RouteAttribute in this case, it would mean that ServiceStack libraries would need to be included as a dependency and shipped together to the client.

IoC Container

ServiceStack has built-in support for dependency injection. To achieve this, it uses a slightly modified version of the Funq[7] framework. Funq is fast and easy to use. ServiceStack has enhanced the basic version of Funq with lifetime scope of the injected objects and therefore supports:

  • ReuseScope.Default: Default scope which is equivalent to ReuseScope.Hierarchy.
  • ReuseScope.Hierarchy: Similar to Singleton Scope. Instances are reused within a container hierarchy. Instances are created (if necessary) in the container where the registration was performed and are reused by all descendent containers.
  • ReuseScope.Container: Singleton scope (an instance is used per application lifetime).
  • ReuseScope.Request: Request scope (an instance is used per request lifetime).
  • ReuseScope.None: Transient scope (a new instance is created every time).

All of the configuration can be done directly in the application host and declaring the objects is not very different than in any other framework.

public class ServiceAppHost : AppHostBase

{

   public override void Configure(Container container)

    {

        container.Register<IOrderRepository>(new OrderRepository());

        container.Register<IProductMapper>(x => new ProductMapper ())

                              .ReusedWithin(ReuseScope.Container);        

    }

}

References will be automatically injected if the service exposes a public property or if it has a constructor, with the parameters being one of the registered IoC types.

public class OrderService : ServiceStack.ServiceInterface.Service

{

    public IOrderRepository OrderRepository { getset; }

    public OrderService(IProductRepository productRepository){ /*..*/}

}

Custom Containers

ServiceStack enables the integration of third-party IoC frameworks through the IContainerAdapter interface. This only exposes two methods.

public interface IContainerAdapter

{

    T Resolve<T>();

    T TryResolve<T>();

}

There are several implementations already available for Microsoft Unity[8], Ninject[9], StructureMap[10], Castle Windsor,[11] and Autofac[12].

Microsoft Unity Container Adapter installation package:

PM> Install-Package ServiceStack.ContainerAdapter.Unity

Ninject Container Adapter installation package:

PM> Install-Package ServiceStack.ContainerAdapter.Ninject

Validation

ServiceStack has a validation framework built around the Fluent Validation library.[13]

When the validation is enabled, the validation framework will check the predefined rules before the service method gets invoked. In the case of a validation error, the ErrorResponse object will be returned with the error details (as shown in Figure 4). It’s good to know that the validation is performed on the server side.

Validation

  1. Validation

To enable the validation, only two operations are needed:

  • Create the validator implementation class: In our case, create the GetOrderValidator class. This class in particular will only be responsible for validating the GetOrdersRequest Request DTO object. The Validator class has to inherit from the AbstractValidator class and specify the Request DTO as the generic parameter type.
  • Register the ValidationFeature and the validator implementation in the application host. This will enable the validation framework and register the particular validator class, in our case GetOrderValidator. Registration is done by using the Plugins.Add() method.

In the following code example, the validator would only be used in the case of GET or POST methods, and this is defined with the RuleSet method. RuleFor instead specifies the rule to be applied for a given DTO property. As you will see, a customized error message can be specified.

public class GetOrderValidator : AbstractValidator<GetOrdersRequest>

{

    public GetOrderValidator()

    {

        //Validation rules for GET request.

        RuleSet(ApplyTo.Get | ApplyTo.Post, () =>

            {

                RuleFor(x => x.Id)

                   .GreaterThan(2)  

                   .WithMessage("OrderID has to be greater than 2");

            });

    }

}

public class ServiceAppHost : AppHostBase

{

    public ServiceAppHost()

         : base("Order Management"typeof(ServiceAppHost).Assembly)

{

    //Enabling the validation.

    Plugins.Add(new ValidationFeature());

    Container.RegisterValidator(typeof(GetOrderValidator));

}

In case of an invalid request, such as GET/orders/1, the framework will return the following error (in cases where the format specified is XML).

<ErrorResponse>

  <ResponseStatus>

    <ErrorCode>GreaterThan</ErrorCode>

    <Message>OrderID has to be greater than 2</Message>

    <StackTrace i:nil="true" />

    <Errors>

      <ResponseError>

        <ErrorCode>GreaterThan</ErrorCode>

        <FieldName>Id</FieldName>

        <Message>'Id' must be greater than '2'.</Message>

      </ResponseError>

    </Errors>

  </ResponseStatus>

</ErrorResponse>

Client Tools

Since ServiceStack exposes standard RESTful web services which are based on pure HTTP, any HTTP-capable client is able to access and consume it. It doesn’t matter which programming language or framework is used; the important thing is the ability to enable communication by using HTTP.

There are several .NET clients currently available: RestSharp,[14] which is an open-source implementation, and several built-in Microsoft .NET ones like HttpClient,[15] WebClient,[16] and HttpWebRequest.[17]

The ServiceStack framework, however, provides its own client implementations that are highly optimized for ServiceStack (e.g., exception handling and routing). There are different implementations of the client, which can be a generic C# client, Silverlight client, JavaScript client, Dart[18] client, or MQ client.[19]

Clients are optimized for the content type. So there is a JsonServiceClient, XmlServiceClient, JsvServiceClient, and two SOAP clients, Soap12ServiceClient and Soap11ServiceClient, for the two current SOAP versions. The difference between the clients is the serializer/deserializer being used. As the following example shows, using a ServiceStack client is relatively easy.

JsonServiceClient client = new JsonServiceClient("http://localhost:50712/");

OrderResponse order = client.Get<OrderResponse>("/orders/1");

Metadata Page

By default, when accessing the web application, ServiceStack exposes a metadata page. The metadata page contains information about the operations, available content types, Web Services Description Language (WSDL), and other objects exposed in the current application host. It is extremely useful because it acts as documentation for the available operations and used types (see Figure 5).

For every format (XML, JSON, etc.) there is an example of an input and output object. This means that we can see what the service accepts as the Request and Response DTOs.

Metadata page

  1. Metadata page

The page is enabled by default. It is available at http://<servername>/metadata, and can be disabled by placing the following code in the application host’s Configure method.

SetConfig(new EndpointHostConfig

{

    EnableFeatures = Feature.All.Remove(Feature.Metadata)

});


Scroll To Top
Disclaimer
DISCLAIMER: Web reader is currently in beta. Please report any issues through our support system. PDF and Kindle format files are also available for download.

Previous

Next



You are one step away from downloading ebooks from the Succinctly® series premier collection!
A confirmation has been sent to your email address. Please check and confirm your email subscription to complete the download.