Book Image

ServiceStack 4 Cookbook

Book Image

ServiceStack 4 Cookbook

Overview of this book

Table of Contents (18 chapters)
ServiceStack 4 Cookbook
Credits
About the Authors
About the Reviewers
www.PacktPub.com
Preface
Index

Up and running with ServiceStack


Let's begin by creating our first service with ServiceStack.

How to do It...

To get started, create an empty ASP.NET solution in Visual Studio. We'll name it HelloWorldService. Next, install the ServiceStack nuget package. Creating a ServiceStack solution with VisualStudio and NuGet in Appendix A, Getting Started has more details on how. ServiceStack is capable of much more than Hello World Service, but doing something simple to start will help us explain some things.

Next, create the first class and call it GreetingRequest. Start by entering a single property Name as follows:

[Route("/hello/{Name}","GET")]
public class GreetingRequest
{
  public string Name { get; set; }
}

Tip

Downloading the example code

You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

This class is now the entry point to our service. We're telling ServiceStack that it can expect HTTP GET requests to a URL /hello with a name parameter— such requests will be deserialized to an instance of the GreetingRequest class.

Next, let's create a service that knows how to handle GreetingRequest by adding another class to HelloWorldService—we can call it GreetingService. To register GreetingService with ServiceStack, we need to implement the IService marker interface. We could also extend the Service helper class, which implements IService and provides useful functionality, as follows:

using ServiceStack;
namespace HelloWorldService
{
    public class GreetingService : IService
    {
        public object Get(GreetingRequest request)
        {
          return "Hello, " + request.Name + "!";
        }
    }
}

What ServiceStack will do is run the GreetingService Get() method whenever an incoming GreetingRequest class requires processing.

ServiceStack's naming conventions for service methods is to name them in a way that indicates which HTTP verbs they expect to process. We could have named our method Any, for instance—if we had, ServiceStack would use our method for GET, POST, PUT, or DELETE requests. If we had named our method Post, our service would refuse to process a GET request, returning a 404 status code with a message that a handler for the request couldn't be found.

Next we'll build an ApplicationHost class that extends ServiceStack's AppHostBase class. You can think of ApplicationHost as a container—it handles the hosting details and dependency injection. If we wanted to quickly migrate our service from Internet Information Services (IIS) to a Windows service, we should only really need to change the ApplicationHost class.

This specific example will be hosted in an ASP.NET application, which is why we extend the AppHostBase class. However, ServiceStack services can be self-hosted, running as a command-line app or Windows service using AppSelfHostBase class.

We need one empty constructor that will pass in the name of the service and the assembly (or assemblies) that ServiceStack can discover your service classes in. It also expects that we'll pass in an IOC container with application configuration, but we don't need that yet, so we'll leave it blank, as follows:

using ServiceStack;
using System.Reflection;

namespace HelloWorldService
{
  public class ApplicationHost : AppHostBase
  {
    public ApplicationHost() : base("Greeting Service",
    typeof(GreetingService).Assembly)
    { }

    public override void Configure(Funq.Container container)
    { }
  }
}

One thing we need to handle is making sure our service gets started when the ASP.NET application boots. We wire that up by calling the Init() method on our ApplicationHost class in the Application_Start handler in Global.asax. First, we'll need to add Global.asax to our project—to do that, right-click the HelloWorldService project, then click on Add, and then click on New Item. Search for Global, choose Global Application Class, and then press Add, as follows:

Visual Studio will bring up the template Global.asax.cs code—just add one line to Application_Start and delete the other methods. When it's done, your code looks like this:

public class Global : System.Web.HttpApplication
{
  protected void Application_Start(object sender, EventArgs e)
  {
     new ApplicationHost().Init();
  }
}

This tells ASP.NET to trigger our ApplicationHost() Init() method when starting this application.

Next, we need to add some configuration in Web.config to tell IIS about ServiceStack—we can do this by adding the following under the <configuration> element:

<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
  <handlers>
    <add path="*" name="ServiceStack.Factory"
      type="ServiceStack.HttpHandlerFactory, ServiceStack"
      verb="*" preCondition="integratedMode"
      resourceType="Unspecified" allowPathInfo="true"/>
  </handlers>
</system.webServer>

Note: these instructions work with IIS7. For instructions on how to make ServiceStack work with IIS6, the https://servicestack.net site has further instruction.

At this stage, we should have a simple, basic service. From here, if you click F5 in Visual Studio, a browser should open showing the default metadata page for a ServiceStack project—as you can see, it lists the different operations available. Clicking on the JSON link next to GreetingRequest will show instructions on how to use it, including an example HTTP request, as follows:

We can easily see our service in action by viewing the /hello/world endpoint. Try replacing world with your name, and the greeting should change too:

How it works...

When IIS starts our application, the Init() method on our ApplicationHost class will be called. Inherited from AppHostBase class, this method initializes our container, any plugins named, and the dependency injection configuration. As with any ASP.NET application, IIS bindings specify which requests will reach our application by specifying port, virtual host information, and so on.

The ServiceStack framework will attempt to deserialize any incoming requests into data transfer objects based on their composition and any routing configuration it has available. In this case, our Route attribute specifies that incoming GET requests with Name parameters should be deserialized into GreetingRequest class:

[Route("/hello/{Name}","GET")]
public class GreetingRequest
{
  public string Name { get; set; }
}

From there, ServiceStack will infer which method should process the DTO. Given that our example request is an HTTP GET request, our Greeting Service's Get() method will be called and presented with the incoming GreetingRequest object:

public object Get(GreetingRequest request)
{
  return "Hello, " + request.Name + "!";
}

It returns a string in this case, which will be presented to the user:

c:\projects>curl http://myserver/hello/world
Hello, world!

There's more...

We're beginning to build up some basic source code, but we don't have any tests yet. Let's see what that looks like:

[TestFixture]
public class GreetingServiceTest
{
  [Test]
  public void ShouldRespondToGreetingRequests()
  {

  }
}

Tip

For basic information on how to get a testing environment running, check out the section Integrating NUnit in Appendix A, Getting Started.

The first thing our test will need is a test request. We can do that easily by creating GreetingRequest and filling in some basic values.

Before we can do that, we'll need to add a reference to the HelloWorldService project, as follows:

We'll pass this request in to our service so that we can make assertions on the response. If you've ever heard people talk about unit testing in terms of Arrange-Act-Assert, this is the Arrange section of the test. Your code might look like this:

[TestFixture]
public class GreetingServiceTest
{
  [Test]
  public void ShouldRespondToGreetingRequests()
  {
    var testRequest = new GreetingRequest { Name = "test value" };
    var target = new GreetingService();
  }
}

We can now execute our service (Act) and make assertions about the response. Let's start with a value that we know will fail to make sure that our test will catch the issue we're trying to find, as follows:

[TestFixture]
public class GreetingServiceTest
{
  [Test]
  public void ShouldRespondToGreetingRequests()
  {
    var testRequest = new GreetingRequest { Name = "test value" };
    var target = new GreetingService();
    var response = target.Get(testRequest);
    Assert.AreEqual("WRONG", response);
  }
}

This being our first test run, we expect the test to fail. You can see that NUnit is explaining to us exactly why it failed. Once we fix it by changing the "WRONG" string to "Hello, test value!", we'll expect it to pass, as follows:

Fixing the test is as simple as writing the following code:

[Test]
public void ShouldRespondToGreetingRequests()
{
  var testRequest = new GreetingRequest { Name = "test value" };
  var target = new GreetingService();
  var response = target.Get(testRequest);
  Assert.AreEqual("Hello, test value!", response);
}

Here's a screenshot depicting the fixed test:

Now that we have a test in place for our service, we can have our IDE run this test (and others like it) frequently so that we can tell if the service stops doing what it's expected to do. The benefit of this can't be understated—bugs found moments after they are created are incredibly simple to fix, whereas bugs found in production can be very expensive to find and resolve.