This articles covers the basic usage of ServiceStack, a .NET-framework for creating RESTful services. The framework has a really great documentation, where you can check out all the details.

Configuration

To get started, you’ll want to create a new ASP.NET project, and load the ServiceStack package via NuGet. Then, you’ll have to edit your Web.config to look like the following (mentioned versions may differ from your project):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="utf-8"?>
<!--
  Informationen zur Konfiguration Ihrer ASP.NET-Anwendung finden Sie unter
  https://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.6.1"/>
    <httpRuntime targetFramework="4.6.1"/>
    <httpHandlers>
      <add path="*" type="ServiceStack.HttpHandlerFactory, ServiceStack" verb="*"/>
    </httpHandlers>
  </system.web>
  <!-- Required for IIS7 -->
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
    <validation validateIntegratedModeConfiguration="false" />
    <handlers>
      <add path="*" name="ServiceStack.Factory" type="ServiceStack.HttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true" />
    </handlers>
  </system.webServer>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs"
        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.5.0, Culture=neutral, PublicKeyToken=31bf3513ad364e35"
        warningLevel="4" compilerOptions="/langversion:default /nowarn:1659;1699;1701"/>
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb"
        type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.5.0, Culture=neutral, PublicKeyToken=31bf3513ad364e35"
        warningLevel="4" compilerOptions="/langversion:default /nowarn:41008 /define:_MYTYPE=\"Web\" /optionInfer+"/>
    </compilers>
  </system.codedom>
</configuration>

The second step is the configuration of the file Global.asax.cs. I’ve created a new class HelloAppHost which inherits from AppHostBase.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class HelloAppHost : AppHostBase
{
    public HelloAppHost() : base("Hello Web Services", typeof(HelloService).Assembly) { }
    public override void Configure(Container container)
    {
        SetConfig(new HostConfig
        {
            DefaultContentType = MimeTypes.Json
        });

        // Authentication
        Plugins.Add(new AuthFeature(() => new AuthUserSession(),
            new IAuthProvider[] {
                new CustomCredentialsAuthProvider()
            }
        ));

        Plugins.Add(new RegistrationFeature());

        container.Register<ICacheClient>(new MemoryCacheClient());
        var userRep = new InMemoryAuthRepository();
        container.Register<IUserAuthRepository>(userRep);
    }
}

I’ve added a authentication functionality, which will be covered later in this post. The other thing I set up, is to return JSON-formatted data as default. The last thing to do in this file is creating an instance of the above class:

1
2
3
4
5
protected void Application_Start(object sender, EventArgs e)
{
    var appHost = new HelloAppHost();
    appHost.Init();
}

Adding Routes

After configuring the service, routes can be added. The general structure consists of three elements: RequestDTO, ResponseDTO and a Service. The following example shows how to set up a route following this approach:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
[Route("/hello/{name*}")]
public class Hello : IReturn<HelloResponse>
{
    public string Name { get; set; }
}

public class HelloResponse
{
    public string Result { get; set; }
}

public class HelloService : IService
{
    public object Get(Hello request)
    {
        var name = request.Name ?? "World";
        return new HelloResponse { Result = $"Hello, {name}!" };
    }
}

This service responds to requests on /hello/{name*}. The curly brackets indicate a variable, the star is a wildcard to indicate, that this variable is optional. This way, the service will also respond if no name is submitted (it will use the default ‘World’ for the response).

While you can use the notation above to mark routes, you can also set these up in your configuration (Global.asax.cs). Just add the following contents after container.register

1
2
3
Routes
    .Add<Hello>("/hello")
    .Add<Hello>("/hello/{Name}");

HTTP Verbs

As shown in the example above, HelloService only implements the method Get(). This can be supplemented or extended by any other HTTP verb or Any, which will then respond to all requests on this path. ServiceStack also has a nice documentation about the usage of each verb.

Fallback Routes

You can use fallbacks to cover routes, that are not handled explicitly. In my case, I return information about the unhandled path and a timestamp. Again, wildcards are used.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[FallbackRoute("/{Path*}")]
public class Fallback : IReturn<FallbackResponse>
{
    public String Path { get; set; }
}

public class FallbackResponse
{
    public string Message { get; set; }
    public string Path { get; set; }
    public String Timestamp { get; set; }
}

public class FallbackService : IService
{
    public object Any(Fallback request)
    {
        return new FallbackResponse {
            Message = "No matching path specified",
            Path = request.Path ?? "/",
            Timestamp = DateTime.Now.ToString()
        };
    }
}

Authentication

The last element I’d like to cover is the authentication of a user. ServiceStack offers the class CredentialsAuthProvider, from which custom providers can be derived. The following example covers two methods, TryAuthenticate, which tries to log in by checking username and password against custom logic, and OnAuthenticated, which will be used to assign session variables.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
    public override bool TryAuthenticate(IServiceBase authService,
    string userName, string password)
    {
        // Only checks if username equals password
        // implement custom logic here
        return userName.Equals(password);
    }

    public override IHttpResult OnAuthenticated(IServiceBase authService,
        IAuthSession session, IAuthTokens tokens,
        Dictionary<string, string> authInfo)
    {
        session.customElement= "Hello World";
        return base.OnAuthenticated(authService, session, tokens, authInfo);
    }
}

After creating this functionality, you can try to log in using the /auth route via POST and adding a username and password parameter. If you want any of your routes to require authentication, just add the [Authenticate] attribute above its response (above the [Route…]). After doing so, requesting this route without earlier authentication will lead to an empty response.

To log out, simply send a request (GET or POST) to /auth/logout.

Further Information

As I mentioned above, ServiceStacks documentation is really well written and maintained. I don’t think you’ll need any information besides what you can find there.