Home Web Development ServiceStack 4 Cookbook

ServiceStack 4 Cookbook

books-svg-icon Book
eBook $32.99 $22.99
Print $54.99
Subscription $15.99 $10 p/m for three months
$10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
BUY NOW $10 p/m for first 3 months. $15.99 p/m after that. Cancel Anytime!
eBook $32.99 $22.99
Print $54.99
Subscription $15.99 $10 p/m for three months
What do you get with a Packt Subscription?
This book & 7000+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook + Subscription?
Download this book in EPUB and PDF formats, plus a monthly download credit
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with a Packt Subscription?
This book & 6500+ ebooks & video courses on 1000+ technologies
60+ curated reading lists for various learning paths
50+ new titles added every month on new and emerging tech
Early Access to eBooks as they are being written
Personalised content suggestions
Customised display settings for better reading experience
50+ new titles added every month on new and emerging tech
Playlists, Notes and Bookmarks to easily manage your learning
Mobile App with offline access
What do you get with eBook?
Download this book in EPUB and PDF formats
Access this title in our online reader
DRM FREE - Read whenever, wherever and however you want
Online reader with customised display settings for better reading experience
What do you get with video?
Download this video in MP4 format
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with video?
Stream this video
Access this title in our online reader
DRM FREE - Watch whenever, wherever and however you want
Online reader with customised display settings for better learning experience
What do you get with Audiobook?
Download a zip folder consisting of audio files (in MP3 Format) along with supplementary PDF
What do you get with Exam Trainer?
Flashcards, Mock exams, Exam Tips, Practice Questions
Access these resources with our interactive certification platform
Mobile compatible-Practice whenever, wherever, however you want
  1. Free Chapter
    Configuration and Routing
About this book
Publication date:
January 2015
Publisher
Packt
Pages
444
ISBN
9781783986569

 

Chapter 1. Configuration and Routing

In this chapter, we'll talk a bit about ServiceStack and we will present the following recipes:

  • Up and running with ServiceStack

  • Routing using data-transfer-object attributes

  • Isolating web service routes from a web application

  • Common ServiceStack plugins

  • Writing a Custom Audit plugin

  • Adding Routes via the API

  • Structuring your project to avoid dependency issues

  • Managing dependencies with Funq and Inversion of Control (IoC)

  • Sharing and accessing configurations and common functionalities using Funq IoC

 

Introduction


ServiceStack is a .NET framework that makes it easy to write web services. It's fast, thoughtfully architected, and by our account, better to work with than Microsoft's own ASP.NET Web API and Windows Communication Foundation (WCF) frameworks. In this book, we'll show you what it's like to work with ServiceStack in a series of recipes that illustrate how to do things using the framework.

ServiceStack helps you to focus on modeling the messages your service will be exchanging with its clients by specifying data transfer objects (DTO). You might start by creating a DTO class to represent an expected HTTP request and provide an annotation on that class that specifies the expected route. A service will later be created that consumes these requests and returns a response DTO. This focus on the façade that your service presents allows you to easily manage the contract between your service and your consuming clients.

ServiceStack has sought out or created components that help it meet its goals of speed and simplicity. While in most cases, you can bring in your favorite frameworks, it provides several out of the box that are well supported:

  • ServiceStack's JsonSerializer is much faster than both Microsoft Base Class Library and DataContractSerializer and faster than other competing open source serializers

  • ServiceStack includes a slightly modified version of the open source Funq DI container known for its performance and simplicity

  • ServiceStack includes ServiceStack.OrmLite, which is much faster than Microsoft's own Entity Framework and most other ORMs

Architecturally, ServiceStack favors a common pattern to develop what can be thought of as RESTful web services. REST is wildly popular today, and many consider it the best approach to a Services-oriented architecture.

Why REST?

Perhaps one of the most compelling reasons to use Representational state transfer (REST) is its focus on developing a design based on the concept of a remote resource. You could imagine that an application based on group messaging would require services where users could exchange messages; client applications would communicate by making HTTP connections to remote resources—the remote resource for a group called My Best Friends might be /groups/MyBestFriends. You could query to see what messages were available request by accessing that URL. You could send new messages to that group by sending an HTTP POST to it—the HTTP POST request could contain a JSON object with the sender's name, the text of the message, and other details. You could just as easily remove this group when it's no longer required by sending HTTP DELETE request to the same endpoint. You could specify that you need only JSON data by sending an Accept header set to application/json or specify that you want a web page by asking for application/html. The RESTful approach of designing a remote resource and then interoperating with that resource through simple HTTP calls naturally extends the Web.

ServiceStack's message-based approach often leads to a simpler service interface. SOAP, Microsoft WCF, and even WebAPI encourage a remote procedure call (RPC) style of programming, which encourages the creation of more and more methods—while a message-based approach encourages you to think about your API. We are aware of one project that took an RPC-based approach over two or three years and ended up with over seventy distinct methods being published. A redesign and the careful application of the message pattern reduced this to just two different REST resources. The result was far more manageable—it was also easier to extend, maintain, test, secure, and document.

While a full treatment of developing REST services is outside the scope of this book, the authors will purposefully take a RESTful approach to building services throughout the example. This is not by accident—and is made much easier when working with ServiceStack.

Note

Note: REST in Practice is a great practical book for getting started on the topic of building RESTful services.

 

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.

 

Routing using data transfer object attributes


ServiceStack routes incoming HTTP requests to services by a number of mechanisms. Perhaps the most convenient is the Route attribute— simply annotate the class to indicate where ServiceStack should expect requests.

Getting ready

You'll need a request object. For instance, Reidson-Industries is interested in developing a group messaging application for use on the Web and on mobile devices. We could model an incoming request like this:

public class Message
{
  public string Body { get; set; }
  public string Sender { get; set; }
  public string GroupName { get; set; }
}

We might handle requests for this Message object with a MessengerService class, as follows:

public class MessengerService : Service
{
  static List<Message> _messages = new List<Message>();
  public MessageResponse Post(Message request)
  {
    _messages.Add(request);
    return new MessageResponse { Response = "OK" };
  }
}

In previous examples, our service methods have simply returned the object, with the service passing a string back. To add a bit more structure to our contract, a response might be modeled like this:

public class MessageResponse
{
  public string Response { get; set; }
}

How to do It...

To tell ServiceStack where to expect requests that contain Message objects, simply annotate the object with a Route annotation, as follows:

[Route("/message")]
public class Message
{
  public string Body { get; set; }
  public string Sender { get; set; }
  public string GroupName { get; set; }
}

How it works...

Now ServiceStack will accept POST requests containing either JSON data or form data at http://yourserver/message containing strings named Body, Sender, and GroupName. These requests will be deserialized in to an instance of the Message DTO. You can provide more information in the annotation as well— for instance, if you wanted to be able to provide an alternate URL format, you could do the following:

[Route("/message")]
[Route("/message/{GroupName}")]
public class Message
{
  public string Body { get; set; }
  public string Sender { get; set; }
  public string GroupName { get; set; }
}

Now, if ServiceStack sees a request for http://yourserver/message/BestFriends, it will assume that Message is destined for the BestFriends group. You can add multiple routes for the same request object by placing multiple Route annotations on the same object.

We'll need to retrieve messages too. We can do that by querying the /group endpoint. To do this, simply create a request object, as follows:

[Route("/group/{GroupName}")]
public class Group
{
  public string GroupName { get; set; }
}

We'll expand MessengerService to be able to handle this request:

public class MessengerService : Service
{
  static List<Message> _messages = new List<Message>();
  public MessageResponse Post(Message request)
  {
    _messages.Add(request);
    return new MessageResponse { Response = "OK" };
  }

  public GroupResponse Get(Group request)
  {
    return new GroupResponse
    {
      Messages = _messages.Where(message => message.GroupName.Equals(request.GroupName))
      .ToList()
    };
  }
}

The GroupResponse class is a simple DTO to model the expected response. In this example, the GroupResponse class has a single property Messages and simple List<Message> containing the messages that the user has requested:

public class GroupResponse
{
  public List<Message> Messages { get; set; }
}

Note

Note that the code in the previous example will work to get us started building a simple application, but storing all of our incoming messages in static List<Message> with no backing store isn't likely to work out well in practice. We'll refactor this into something more production-ready in a later recipe.

Once you start the app, you can send a form post to the BestFriends group with curl. A command-line HTTP utility, curl makes it easy to craft full-featured HTTP requests. It can specify headers and HTTP methods, send form data, and return any results on the command line.

We want to send an HTTP POST request with enough form data to provide a message to our service, and we'd like to see the response in JSON. We'll use curl with -H to specify the header, -X, to specify the HTTP method, and --data to specify the data to send. Put together, it looks like this:

curl -H "Accept: application/json" -X POST --data  \
    "Body=first post&Sender=Kyle&GroupName=BestFriends" \
    http://myserver/message

Then, you can read the messages that have been sent to the BestFriends group, as follows:

curl -H "Accept: application/json" \     
     http://myserver/group/BestFriends

The result would be the JSON response, as follows:

{"Messages": [{"Body":"first post", "Sender":"Kyle","GroupName":"BestFriends"}]}

There's more...

Let's imagine that we wanted people to be able to search for a specific search term or possibly search for a term within a specified group. We could use the Route annotation to do this easily with one single request type. Implement it like this:

[Route("/message/search")]
[Route("/message/search/{Group}")]
public class Search
{
  public string Group { get; set; }
  public string Query { get; set; }
}

We'll easily expand our MessengerService class to be able to handle this request by adding a new method, as follows:

public GroupResponse Get(Search request)
{
    return new GroupResponse
    {
      Messages = _messages.Where(
        message => message.GroupName.Equals(request.Group)
        && message.Body.Contains(request.Query))
      .ToList()
    };
}

We could make use of this new endpoint with another curl command. First, we'll post a few messages so that we have something to search, as follows:

curl -H "Accept: application/json" -X POST \
     --data "Body=first post&Sender=Kyle"  \
     http://myserver/message/BestFriends
{"Response":"OK"}
curl -H "Accept: application/json" -X POST \
     --data "Body=second post&Sender=Kyle"  \
     http://myserver/message/BestFriends
{"Response":"OK"}

Then, we can easily search by sending a simple GET call:

curl -H "Accept: application/json" \    
    http://myserver/message/search/BestFriends?query=second
{"Messages":
  [
    {"Body":"second post",
     "Sender":"Kyle",
     "GroupName":"BestFriends"}
  ]
}
 

Isolating web service routes from a web application


Until now, we've been talking about using ServiceStack in isolation, where it's the only thing handling all requests. It won't always be so simple, of course— sometimes you'll want to use ServiceStack in an existing MVC, WCF, or WebForms application. Here, we will learn different ways to isolate ServiceStack requests to ensure they don't get tangled up with requests from other frameworks.

Getting ready

For this example, let's keep building on ReidsonMessenger from the first recipe, but namespace the HTTP contract of our API by moving all of our service endpoints under a prefix. So, instead of making a GET call to /group/BestFriends to retrieve the messages from the BestFriends group, we'll be calling /api/group/BestFriends.

How to do It...

We'll need to configure the web server to facilitate our new prefix. We'll add the following to Web.config, just after the system.web section:

 <location path="api">
    <system.web>
      <httpHandlers>
        <add path="*" type="ServiceStack.HttpHandlerFactory, ServiceStack" verb="*" />
      </httpHandlers>
    </system.web>

    <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>
  </location>

After making this change, running our application might return an error message as we continue visiting http://myserver/— remember to add the api path at the end to see the usual metadata page you're expecting. We'll need to change the URLs we post to use curl too, as follows:

curl http://myserver/api/group/BestFriends

While not strictly necessary, one benefit of using the location element is the ability to remove other handlers, ensuring that ServiceStack is the only thing running on this path.

If it makes more sense to make this change in code, ServiceStack allows this to be changed within your AppHost.Configure method, as follows:

public override void Configure(Funq.Container container)
{
  SetConfig(new HostConfig
  {
    HandlerFactoryPath = "api"
  }
}

In your organization, if developers have a lot of control over deployment of code, it might make sense to control this in code, as then it can be more easily tested, and you might find it more expressive. However, if another team deploys your code or manages your application in production or if you want to be able to tune this location often, it might be preferable to specify the path in the web config file, as then changing it won't require a complete compile, test, and deploy cycle.

How it works...

When using any HTTP handlers with ASP.NET, a path must be registered to tell IIS how to handle requests of a specific path. ServiceStack provides its HttpHandlerFactory implementation, which is the initial hook into the rest of the framework.

By either changing the path in web.config or setting the path when your application starts, we can make a clear separation between our web services and other resources. There are important differences between the two methods.

By changing the path within the configuration, you'll notice that when you start up your web project, you are greeted with this:

This is because ServiceStack is not actually handling your request and there is no default item within the solution that ASP.NET can serve.

By changing HostConfig and leaving web.config path as "*", ServiceStack is serving all your other resources as well. So, as soon as you run your application, ServiceStack will default to your new web services path as follows:

The following screenshot shows you the metadata page:

If you happen to be hosting files with uncommon file extensions, it's important to remember that if the ServiceStack handler path is configured as "*", ServiceStack needs to know what file types are able to be served.

For example, if you are writing your web client using something like Dart, which uses .dart files for it's source, both ASP.NET and ServiceStack need to know about this additional file type that is allowed. Perform the following steps towards this end:

  1. ASP.NET will need to know about the appropriate file extension and MIME type, for example:

        <staticContent>
          <remove fileExtension=".dart" />
          <mimeMap fileExtension=".dart" mimeType="application/dart" />
        </staticContent>
  2. ServiceStack will need to have the file extension added to the AllowFileExtensions property on HostConfig():

        var hostConfig = new HostConfig();
        hostConfig.AllowFileExtensions = {"dart"};
        hostConfig.HandlerFactoryPath = "api";
        SetConfig(hostConfig);

There's more...

ServiceStack can also be hosted in various environments including as a Windows service or even a simple console application. In this case, the initializer for the service is a call to the Start method on the AppHost, which accepts a parameter that represents the URL to bind to. If a prefix is required, it will need to be included into this urlBase parameter, as follows:

class Program
{
  const string ListeningOn = "http://*:1234/api/";
  static void Main(string[] args)
  {
    new AppHost()
    .Init()
    .Start(ListeningOn);

    Console.WriteLine("AppHost Created at {0}, " + "listening on {1}",DateTime.Now, ListeningOn);

    Console.ReadKey();
  }
}
 

Common ServiceStack plugins


There are some requirements that are very common when building web services. For instance, many sites need to validate user input, log requests, or manage the security of the application. ServiceStack comes with some plugins that are very simple to add and that provide advanced functionality through a simple interface. This recipe shows how these features can be added using some of the default plugins available.

How to do It...

There are quite a few plugins that ServiceStack v4.0 comes with, and they are all added the same way; some are standalone, some have dependencies, but they all implement the IPlugin interface. The following are a few examples showing how the required code is added to AppHost in the overridden Configure method:

ValidationFeature enables the use of Fluent Validation to construct easy to read rules. A common usage of these rules is validation of request values before ServiceStack executes the HTTP method of your service:

Plugins.Add(new ValidationFeature());

RegistrationFeature provides new web service endpoints to enable user registration. This feature is commonly used with AuthFeature:

Plugins.Add(new AuthFeature(() => new AuthUserSession(),
new IAuthProvider[]
{
   new BasicAuthProvider()
}));
Plugins.Add(new RegistrationFeature());

CorsFeature enables your web services to support Cross-Origin Resource Sharing (CORS). This allows JavaScript clients on other domains to use your web services:

Plugins.Add(new CorsFeature());

How it works...

The ServiceStack plugins object is just List<IPlugin> that is accessible from your AppHost class.

CorsFeature and ValidationFeature both utilize ServiceStack request filters to enable functionality for each request that is sent to your web services.

AuthFeature and RegistrationFeature create new endpoints to expose functionality as well as enable the use of AuthenticateAttribute to decorate your service classes. You can see this if you look at the metadata page of your application after adding AuthFeature; you'll notice the additional endpoints your application is now hosting.

The following screenshot depicts few of the plugins provided by the ServiceStack framework:

AuthFeature and RegistrationFeature have added four endpoints to enable functionality such as authenticating users and the registration of new ones. The implementation specifics of this depend on how these objects are created.

Plugins are a powerful way to expose reusable functionality across ServiceStack apps with minimal effort. The previous screenshot shows just a few of the plugins that the ServiceStack framework provides. It's easy to add the class implements IPlugin, it can be registered with ServiceStack and will be processed at start-up of the application.

 

Writing a custom audit plugin


In the ServiceStack framework, plugins are a great way to encapsulate completely independent functionality that can be reused between projects. ServiceStack itself bundles loads of useful packages this way, including authentication, validation, and others.

In this recipe, we will build a plugin to add an audit to our database's create and update methods—you might find this useful if your project requires auditing for changes to a data source. We'll make use of OrmLite features to do so.

How to do It...

Create a new class library project that will contain your plugin and all its required components—AuditFeaturePlugin.

Add ServiceStack and its dependencies as references to the new project.

Create an interface for objects you want to audit called IAuditable:

public interface IAuditable
{
    DateTime CreatedDate { get; set; }
    DateTime ModifiedDate { get; set; }
    string ModifiedByUserId { get; set; }
}
Create a class that implements IPlugin.
public class AuditFeature : IPlugin
{
  public IDbConnectionFactory DbConnectionFactory { get; set; }

  public void Register(IAppHost appHost)
  {
    if (OrmLiteConfig.DialectProvider == null)
    {
      throw new Exception("AuditFeature requires the use of OrmLite and a DialectProvider must be first initialized.");
    }

    OrmLiteConfig.InsertFilter = AuditInsert;
    OrmLiteConfig.UpdateFilter = AuditUpdate;
  }

  private void AuditInsert(IDbCommand command, object rowObj)
  {
    var auditObject = rowObj as IAuditable;
    if (auditObject != null)
    {
      var now = DateTime.UtcNow;
      auditObject.CreatedDate = now;
      auditObject.ModifiedDate = now;
      // Modified by user running the process of the AppPool. Note: only works in Windows.
      auditObject.ModifiedByUserId =System.Security.Principal.WindowsIdentity.GetCurrent().Name;
    }
  }

  private void AuditUpdate(IDbCommand command, object rowObj)
  {
    var auditObject = rowObj as IAuditable;
    if (auditObject != null)
    {
      var now = DateTime.UtcNow;
      auditObject.ModifiedDate = now;
      // Modified by user running the process of the AppPool. Note: only works in Windows.
      auditObject.ModifiedByUserId =System.Security.Principal.WindowsIdentity.GetCurrent().Name;
  }
  }
}

Now that we have created a separate class library that contains our AuditFeature plugin, we can share it with the main project that is hosting the ServiceStack web services. Remember to add a reference to the main project so that both the IAuditable interface and the AuditFeature plugin itself are able to be used.

Register the plugin from within your ApplicationHost class:

public class ApplicationHost : AppHostBase
{
  public ApplicationHost(): base("Reidson Messenger", typeof(MessageRequest).Assembly)
  { }

  public override void Configure(Container container)
  {
    Plugins.Add(new AuditFeature());
  }
}
Add the IAuditable interface to a model class, like the Message class:
public class Message : IAuditable
{
  //...
  public DateTime CreatedDate { get;set; }
  public DateTime ModfiedDate { get;set; }
  public string ModfiedByUserId { get;set; }
}

How it works...

IPlugin that ServiceStack provides has one single method that ServiceStack calls when the framework is initializing.

In the case of the AuditFeature class, a check is made to make sure that OrmLite is being used in the project that is running the AuditFeature function by checking whether DialectProvider is currently being used with OrmLite.

Once this is done, it binds an action to both InsertFilter and UpdateFilter provided by OrmLite. These actions are fired whenever an insert or an update is processed using the OrmLite framework.

See also

  • Using Ormlite filtering for custom actions on insert/update

 

Adding Routes via the API


This recipe covers the ability to add routes without using the provided RouteAttribute class. This technique might be needed if you have restrictions on your development environment or requirements that might prevent you from using RouteAttribute. In this situation where it's not ideal or possible to use the ServiceStack C# client, a client such as RestSharp with data transfer objects might be possible alternative.

Note

Using the routing attributes gives you the advantages of more streamlined development when using the ServiceStack JsonClient and is the recommended way of managing your application's routes. The solution in this recipe is only intended for situations where this is not possible.

How to do It...

From the AppHost class, access the Routes property on the base ServiceStackHost class to add routes, passing the request object's type and the path to be used:

public class AppHost : AppHostBase
{
  public AppHost(): base("Adding Routes via AppHost", typeof(AppHost).Assembly)
  { }
  
  public override void Configure(Container container)
  {
    Routes.Add<GreeterRequest>("/greetings/{Name}");
    Routes.Add<FarewellRequest>("/farewell/{Name}", "GET");
    Routes.Add<HowAreYouRequest>("/howareyou/{Name}", ApplyTo.Get);
    Routes.Add<IntroRequest>("/introducing/{0}/and/{1}",ApplyTo.Get,request => request.FirstName,request => request.SecondName);
    Routes.Add<IntroRequest>("/introducing/{0}/and/{1}/otherway",ApplyTo.Get, request => request.SecondName, request => request.FirstName);
    Routes.AddFromAssembly(typeof(ImFromRequest).Assembly);

  }
}

How it works…

Using this recipe, routes are registered directly with the ServiceStackHost class using two methods.

  • Routes.Add<Type>(path): This is a single registration of a request type and a path, which will map the URL to the service associated with the request object, in this case GreeterRequest is associated with the URL /greetings/{Name}. The {Name} URL binds the value in the place of the path to the Name property of the request object.

  • Routes.Add<Type>(path,"GET, POST, DELETE"): This is another way to register the route with the same passing of property values, but restricting the request to just the verb methods specified. If the verb isn't specified, it won't be available. If you try to access a route that hasn't been registered with the verb being requested, ServiceStack will respond with a 404 status code and default page advising you that the route was not found.

  • Routes.Add<Type>(path, ApplyTo.Get): This is the same as using a string of verbs to restrict the path, but can be useful when trying to avoid possible bugs from spelling mistakes in the list of verbs.

  • Routes.Add<Type>(pathWithFormater, ApplyTo.Get, propertyExpressions): This is an extension method to use for ordered variables to be used map properties to values within the path. This can be useful if you register different mappings with different verb restrictions or when dealing with complex routes that may have different binding behavior. In the example shown, by adding otherway to the end of the same route, we changed the binding behavior of the same service.

  • Routes.AddFromAssembly(assembly): This is a method that requires the use of RouteAttribute to find request objects with routes within a specified assembly.

  • The add method also provides a way to register types that are only known at runtime with alternate methods such as Routes.Add(myTypeInstance, path). This could be used in conjunction with standard .NET reflection methods such as myObjectInstance.GetType(), which can be used on any object.

There's more...

In versions of ServiceStack greater than 4.0.18.0, the GetRouteAttributes(Type type) method is virtual, allowing it to be overridden. This can allow the ability to source an array of RouteAttribute objects from custom locations or using custom logic.

For example, when the server's AppHost class is starting up, this method could check some custom configuration or even call external web services to work out what routes should be used. To achieve this, simply override the GetRouteAttributes method in a suitable place in your code.

 

Structuring your project to avoid dependency issues


When building up your project, it's important to choose a file structure that matches your architecture and simplifies your life as much as possible. For instance, projects that are considering an application with a service layer, a business model, and a repository layer might create a structure like this:

\CrudService
\CrudService\Models
\CrudService\Repositories
\CrudService\Services
\CrudService.Tests
\CrudService.Tests\Models
\CrudService.Tests\Repositories
\CrudService.Tests\Services

With ServiceStack and other frameworks that make use of strongly typed data transfer objects, it can make sense to have the DTOs themselves shared across both a client project, for instance, a ServiceStack C# client, and the server project, particularly when one team is in charge of both—this helps each project to immediately and automatically stay in sync on any changes to the DTOs.

We'll go into more depth on the C# client later in the Integrating with ServiceStack using the C# client and NativeTypes recipe in Chapter 9, Integrating with Other Technologies.

Getting ready

First make sure that your main project is broken up appropriately—creating folders for services and other layers for instance.

Secondly, create a new project within your solution for the data transfer objects. In our example, we'll call this project ServiceModel.

When that's done, we'll add a reference from the main project to the ServiceModel project.

When we create our client project after that, we'll add a reference only to the ServiceModel folder at that time, creating a clean line of separation between our projects. This leads to less coupling of our code and a more flexible interface.

While any unit test project will still require a reference to the main project, any integration test projects might not, depending on what all you're doing. Integration test projects will only require a reference to the ServiceModel project, as with our client.

How to do It

First, let's build on the service we created in the Routing using data transfer object attributes recipe, about the Route annotation. However, we'll refactor things a bit, creating a Service folder, and then creating a ServiceModel project. When you're finished, your project should look like this:

MessengerService.cs has been moved out to the Service folder, but nothing else has changed. Fix your namespaces, make sure things still build, and check that any tests still pass, as shown in the following screenshot:

Once that's done, our next step is to create the ReidsonMessenger.ServiceModel project—a class library will do fine.

Next, we'll move all of our data transfer objects to ServiceModel. You can do it one at a time, or highlight all six of them and drag-and-drop. Make sure you get Group.cs, GroupResponse.cs, Search.cs, SearchResponse.cs, Message.cs, and MessageResponse.cs in the new project, and you can delete them from the old one.

Once you've done that, the project won't build anymore. To fix that, add a reference from the main project to the ServiceModel project:

If you have any test projects, they'll need the reference too.

Once the references are in place, you need to add the using directives for each class that makes use of the DTOs. Once that's done, your project should build again, with tests still passing.

Now you can add a client project to your solution, and it would only need a reference to ServiceModel. To demonstrate, go ahead and add a ServiceClient project to the solution. Right-click the solution and choose New Project. Choose Console Application as the type, enter the name ServiceClient.

Note

Note that if you're using VisualStudio Express for Web, you can instead create a class library and then change the type to Console Application in the project properties.

You'll also need to add a reference to ServiceStack as usual.

Once the references are added, you could create a client as follows:

public class Program
{
  public static void Main(string[] args)
  {
    Console.WriteLine("Please enter your name:");
    var sender = Console.ReadLine();
    Console.WriteLine(
     "Please type the group name you'd like to post to:");
    var groupName = Console.ReadLine();
    Console.WriteLine("Please enter your message:");
    var body = Console.ReadLine();
    var message = new Message
    {
        Body = body,
        GroupName = groupName,
        Sender = sender
    };

    var client = new JsonServiceClient("http://localhost:2202");
    client.Post<MessageResponse>(message);
    Console.WriteLine(
      "Thank you. To read messages for " + groupName + ", please push any key.");
    Console.ReadKey();

Next up, we can query the service by calling client.Get(), passing in a request object, and specifying the response type we're looking for. We'll receive a response containing the messages we'd like to display. A simple foreach loop should do the trick of displaying them:

    var messages = client.Get<GroupResponse>(new Group { GroupName = groupName });

    Console.WriteLine("Displaying " + messages.Messages.Count + " messages:");
    foreach (var groupMessage in messages.Messages)
    {
      Console.WriteLine(groupMessage.Sender + ": "+ groupMessage.Body);
    }
    Console.ReadKey();

As you can see, with the one simple reference to ServiceModel, ServiceStack itself, and a starting URL, we can easily construct clients that can connect to the service without having any other references, reading documentation for the REST service, or needing to know the exact paths specified in the routes.

We'll describe the C# client in more detail in Chapter 9, Integrating with Other Technologies.

 

Managing dependencies with Funq and Inversion of Control (IoC)


Until now, ReidsonMessenger has stored all of its messages in a static List<Message> attached to MessengerService. This isn't a great design for a number of reasons—if our app restarts, all previous messages are lost. That's really just the beginning though; it's also not at all thread-safe. If two clients connect to our server and try to read or write messages at the same time, we're likely to see problems.

Let's refactor our code to fix the problem. The first thing we notice is that our existing implementation is a bit difficult to remove. We have a dependency on this static list—and all of our code in the MessengerService assumes that messages are stored in a List<Message> that we can access directly.

Let's start by making it easy to remove static List<Message> by wrapping it in a repository class. While we're at it, though, let's begin using Funq to inject this dependency to make our life easier—while we're experimenting with fixing the issue, we don't want to break the code.

This process of using IoC to replace an existing component with a new one while keeping the software working is sometimes referred to as "Branching by Abstraction". Instead of creating a separate feature branch of our software, we can keep working on the trunk, but get the benefits of creating our new implementation safely without interrupting production.

Getting ready

  1. First, we'll write a test that illustrates the problem we're trying to solve—that the current implementation isn't thread-safe.

  2. Since our theory is that the static list is at fault, we'll refactor the list so that it's not a field inside of our service anymore—we'll create a new class called StaticMessagesRepository, and move the static list into this new class. We'll make adjustments to our service to make calls to this class instead of accessing the list directly. We do this so that we can easily replace this working but flawed implementation with our new one.

  3. We'll create an interface that covers the most important functionality for StaticMessageRepository—the method to Add new messages—and another method that accepts Predicate<Message,bool> and returns IEnumerable<Message>. This allows us to take a dependency on this interface, not the specific implementation, in our service. That makes it easier for us to swap it in the AppHost.Configure method, allowing us to keep control over which implementation to use in that central location.

  4. Next, we'll start wiring up the messages repository with Funq. We'll set up our production AppHost class to wire up our existing but flawed StaticMessagesRepository, but we'll start working on a new implementation that leverages OrmLite. In our tests, we'll test the new OrmMessagesRepository until it solves the problem and is working. When we're through, we can simply change the AppHost.Configure method in our production AppHost class to use the newly tested implementation.

  5. Once all of our tests pass, and we've been in production a little while, we can remove the old StaticMessagesRepository as it has outlived its usefulness.

Note

For more information on the Branch by Abstraction technique, the canonical article can be found on Martin Fowler's site at http://martinfowler.com/bliki/BranchByAbstraction.html.

How to do It…

  1. Let's start by developing a unit test that shows the problem we're talking about. We can illustrate the problem with a simple Parallel.ForEach method that will run lots of commands against the list until it eventually throws an exception:

    [Test]
    public void ShouldBeThreadSafe()
    {
      var service = new MessengerService();
      const string testGroupName = "Main";
      const int iterations = 200;
    
      Parallel.ForEach(
        Enumerable.Range(1, iterations),
        iteration =>
        {
          service.Post(new Message
          {
            Body = "Post {0}".Fmt(iteration),
            Sender = "Sender",
            GroupName = testGroupName
          });
          service.Get(new Search
          {
            Group = testGroupName,
            Query = "Post"
          });
        });
                
      var testGroup = service.Get(new Group
      {
        GroupName = testGroupName
      });
                
      var randomSearchString = "Post {0}".Fmt(
        new Random().Next(1, iterations));
    
      Assert.AreEqual(1, testGroupMessages
        .Messages
        .Count(m => m.Body.Equals(randomSearchString)));
    }

    On the author's machine, this test fails with this exception:

    System.InvalidOperationException : Collection was modified; 
    enumeration operation may not execute. 

    This happens because the collection was modified by an Add method while we were trying to read from the collection, as expected.

  2. Since we think that the static List<Message> is the problem, we'll make changes to the original service to isolate it for removal. Instead of just having List<Message> as a field on MessengerService, we'll wrap it in a class, and then use this new class for access. This class will implement an IMessageRepository interface in order to allow us to easily replace it later with a better implementation. The code for this procedure is as follows:

    public interface IMessageRepository
    {
      void Add(Message message); 
      IEnumerable<Message> Where(Func<Message, bool> predicate);
    }
    public class StaticMessageRepository 
      : IMessageRepository
    {
      static List<Message> _messages = new List<Message>();
    
      public void Add(Message message)
      {
        _messages.Add(message);
      }
    
      public IEnumerable<Message> Where(Func<Message, bool> predicate)
      {
        return _messages.TakeWhile(predicate).ToList();
      }
    }
  3. Now we'll refactor our service to use the new wrapper class instead of directly accessing static List<T>. We call this change a refactor because the end result should be functionally equivalent; only the organization of the code has changed. We'll also change MessengerService to rely on Funq to provide IMessageRepository in the future:

    public class MessengerService : Service
    {
      public IMessageRepository MessageRepository { get; set; }
    
      public object Post(Message request)
      {
        MessageRepository.Add(request);
        return new MessageResponse { Message = "OK" };
      }
    
      public object Get(Group request)
      {
        return new GroupResponse
        {
          Messages = MessageRepository.Where(
            message => message
              .GroupName.Equals(request.GroupName))
          .ToList()
        };
      }
    
      public object Get(Search request)
      {
        return new SearchResponse
        {
          Messages = MessageRepository.Where(
            message => message
              .GroupName.Equals(request.Group)
              && message.Body.Contains(request.Query))
          .ToList()
        };
      }
    }
  4. Now, we'll create BasicOrmMessageRepository, a fresh, basic implementation using OrmLite, just enough to get it working. We can improve it with other refactoring later; it is important for now not to break our existing code. Here's how our code looks:

    public class BasicOrmMessageRepository : IMessageRepository
    {
      public IDbConnectionFactory DbConnectionFactory 
      { get; set; }
    
      public void Add(Message message)
      {
        using (var db = DbConnectionFactory.OpenDbConnection())
        {
          db.Insert(message);
        }
      }
    
      public IEnumerable<Message> Where(
        Func<Message, bool> predicate)
      {
        using (var db = DbConnectionFactory.OpenDbConnection())
        {
          var allDatabase = db.Select<Message>();
          var results = new List<Message>();
          allDatabase.ForEach(m =>
          {
            if (predicate(m)) results.Add(m);
          });
          return results;
        }
      }
    }

    An astute reader might have noticed that the database code shown previously really isn't a great OrmLite implementation. It's quite likely that your database performance tests are going to notice a big slowdown with this implementation once the service has more than a few thousand messages as our search code simply fetches the entire database of messages into memory, loops them over, and checks them one by one for a match.

    For now, we're forced into this implementation because we're trying to honor the existing contract, and OrmLite can't accept a raw predicate unlike our static list. OrmLite's Select() requires Expression<Func<Message,bool>> and not just Func<Message,bool>. This naive implementation gets us around that particular problem for now.

    The good thing about this naive implementation is that it is completely compatible with the old one, so we can keep working on the new one while we coexist with the old implementation. We'll need to solve this performance problem, of course—we'll come back to this before the recipe is up, refactoring as we go.

  5. Next, let's go into TestFixtureSetUp and wire up our new dependency. We'll also add code to a SetUp method that drops and recreates the table we'll use before any test. Once we're sure that the new implementation is better than our static list, we'll add similar code to AppHost:

    [TestFixtureSetUp]
    public void FixtureSetUp()
    {
      _appHost = new BasicAppHost
      {
        ConfigureContainer =
          container =>
            {
              container.RegisterAutoWiredAs<
                BasicOrmMessageRepository, IMessageRepository>();  
              container.RegisterAutoWired<
                MessengerService>();
              var dbFactory = new OrmLiteConnectionFactory(
                "~/App_Data/db.sqlite".MapHostAbsolutePath(), 
                SqliteDialect.Provider);
              container.Register<IDbConnectionFactory>(
                dbFactory);
            }
      }.Init();
    }
    
    [SetUp]
    public void SetUp()
    {
      using (var db = _appHost.Resolve<IDbConnectionFactory>()
      .OpenDbConnection())
      {
        db.DropAndCreateTable<Message>();
      }
    }
  6. As soon as we drop this code in place, however, our tests start having problems. It turns out that OrmLite doesn't like our use of .Equals() in the predicate. We'll have to change MessengerService to accommodate that using == instead, which it can handle. Here's how the code for the procedure described in this paragraph looks:

    public object Get(Group request)
    {
      return new GroupResponse
      {
        Messages = MessageRepository
        .Where(message => message.GroupName == request.GroupName)
        .ToList()
      };
    }
    
    public object Get(Search request)
    {
     return new SearchResponse
     {
       Messages = MessageRepository
           .Where(message => message.GroupName == request.Group && message.Body.Contains(request.Query))
       .ToList()
     };
    }
  7. With this code in place, the tests should now pass! Our OrmMessageRepository file solved the concurrency issue. Now it's time to go back and fix the performance issue.

  8. Again, we'll start with a test to prove our theory that BasicOrmMessageRepository isn't fast enough. We'll create TestFixtureSetup that configures BasicAppHost to wire up BasicOrmMessageRepository and a Setup method that we'll run before each test and that creates a large database of records to test against. Our test can then search the repository for a random record and time it to see how long it takes. We'll set higher bounds of 150 milliseconds for now. Here's how the code for our test looks:

    [TestFixture]
    public class BasicOrmMessageRepositoryPerformanceTests
    {
      const int LargeMessageCount = 100000;
      ServiceStackHost _appHost;
    
      [TestFixtureSetUp]
      public void FixtureSetUp()
      {
        _appHost = new BasicAppHost
        {
          ConfigureContainer =
            container =>
            {
              container.Register<IDbConnectionFactory>(
                new OrmLiteConnectionFactory(
                  "~/App_Data/db.sqlite".MapHostAbsolutePath(),
                  SqliteDialect.Provider));
              container
                .RegisterAutoWired<BasicOrmMessageRepository>();
            }
        }.Init();
      }
    
      [SetUp]
      public void SetUp()
      {
        const string testDataFile = 
        @"../../OrmMessageRepository_Performance_Test_Data.json";
    
        if (!File.Exists(testDataFile))
        {
          CreateTestFile(testDataFile, LargeMessageCount);
        }
    
        using (var db = _appHost
          .Resolve<IDbConnectionFactory>().OpenDbConnection())
        {
          db.DropAndCreateTable<Message>();
          var wholeList = File.ReadAllText(testDataFile)
            .FromJson<List<Message>>();
          db.InsertAll(wholeList);
        }
      }
    
      [TestFixtureTearDown]
      public void FixtureTearDown()
      {
        _appHost.Dispose();
      }
    
      [Test]
      public void ShouldHandleLargeMessageCountEffeciently()
      {
        var repo = _appHost.Resolve<BasicOrmMessageRepository>();
    
        var randomSearchString = "Message {0}".Fmt(
          new Random().Next(1, LargeMessageCount));
    
        var searchTimer = new Stopwatch();
        searchTimer.Start();
        var testSearchRecords = repo.Where(
          message => message
            .Body
            .Contains(randomSearchString));
        searchTimer.Stop();
    
        Assert.AreEqual(
          randomSearchString, 
          testSearchRecords.First().Body);
        Assert.Less(searchTimer.ElapsedMilliseconds, 150);
    
      }
      void CreateTestFile(string fileName, int testRecords)
      {
        Console.WriteLine("Creating test data...");
        var tmp = new List<Message>();
        foreach (int iteration in 
          Enumerable.Range(1, testRecords))
        {
          tmp.Add(new Message
          {
            Body = "Message {0}".Fmt(iteration),
            GroupName = "performance test group",
            Sender = "test sender"
          });
    
        }
    
        var wholeList = tmp.SerializeToString();
        File.WriteAllText(fileName, wholeList);
      }
    }

    Running this test should show a failure as with BasicOrmMessageRepository; we can't actually search through 100,000 records in less than 150 milliseconds. On my machine, it takes ~ 800 milliseconds, which will only get worse as we add messages.

  9. Now that we have a failing test, again we can set out to fix the problem. The best way to do this is to allow OrmLite to run our predicate in the database engine instead of downloading the whole database and running the predicate in memory. However, as we know, OrmLite's Select() method requires Expression<Func<Message,Bool>>, and right now we only accept a Func<Message,Bool> function. Let's start by refactoring the interface and the basic static list, then refactoring BasicOrmMessageRepository to make it a bit smarter:

    public interface IMessageRepository
    {
      void Add(Message message);
    
      IEnumerable<Message> Where(
        Expression<Func<Message, bool>> predicate);
    }
    public class StaticMessageRepository : IMessageRepository
    {
      static List<Message> _messages = 
        new List<Message>();
    
      public void Add(Message message)
      {
        _messages.Add(message);
      }
    
      public IEnumerable<Message> Where(
        Expression<Func<Message, bool>> predicate)
      {
        return_messages.TakeWhile(predicate.Compile()).ToList();
      }
    }
  10. Now that we've changed the method signature on the interface and updated our StaticMessageRepository implementation, we need to update BasicOrmMessageRepository too or our code won't compile. Here's how we do that:

    public class BasicOrmMessageRepository : IMessageRepository
    {
      public IDbConnectionFactory
        DbConnectionFactory { get; set; }
    
      public void Add(Message message)
      {
        using (var db = DbConnectionFactory.OpenDbConnection())
        {
          db.Insert(message);
        }
      }
    
      public IEnumerable<Message> Where(Expression<Func<Message, bool>> expression)
      {
        using (var db = DbConnectionFactory.OpenDbConnection())
        {
          return db.Select(expression);
        }
      }
    }
  11. With these changes, our original concurrency is solved, and so is our performance problem! Of course, our main service is still using StaticMessageRepository. Let's go back and wire it up in the production AppHost class:

    public class AppHost : AppHostBase
    {
      public AppHost() : base("Reidson Industries GroupMessenger",typeof(MessengerService).Assembly) { }
      public override void Configure(Funq.Container container)
      {
        var dbFactory = new OrmLiteConnectionFactory("~/App_Data/db.sqlite".MapHostAbsolutePath(),SqliteDialect.Provider);
    
        container.Register<IDbConnectionFactory>(dbFactory);
    
        container.RegisterAutoWiredAs<BasicOrmMessageRepository,IMessageRepository>();
    
        using (var db = dbFactory.OpenDbConnection())
        {
          db.DropAndCreateTable<Message>();
        }
      }
    }

How it works…

The basic pattern of this recipe is to build tests to prove the problem we're trying to solve, to build new implementations that pass the tests, then to use Funq IoC to switch implementations when new ones are ready. The previous code is a typical example of where we didn't necessarily plan ahead of time to make a component replaceable—we realized it as we recognized a problem. We showed realistic techniques to deal with this, making use of automated tests, interfaces, refactoring, and dependency injection.

While the Branch by Abstraction process might seem like it takes a little bit longer to get your code into the application, you reduce risk significantly by keeping your tests passing the whole time. You also reduce risk by not replacing something that works, albeit imperfectly, until your replacement is an actual improvement, all without needing to create a long-lived feature branch.

 

Sharing and accessing configuration and common functionality using Funq IoC


A pattern that ServiceStack encourages with its design is the use of IoC containers. While you can use most common IoC containers with ServiceStack, it defaults to Funq. Funq was adopted due to its excellent performance and memory characteristics, and it also exposes a simple, clean API.

In this recipe, we will look at sharing application settings and other common objects from our services with the use of the Funq IoC container. We will also look at how ServiceStack can help with accessing application settings in web.config or app.config.

Getting ready...

In ASP.NET, a common way to store configurations is by having those settings in either the web.config or the app.config file of your application. We will first need to have some configuration settings to store, which we are going to use in our code for various tasks. In this recipe, we are going to store the following:

  • A connection string to our SqlLite database

  • A list of e-mail addresses to identify administrators of the application

  • Some environment-specific settings for integrated systems

These three examples will illustrate how to take advantage of some of the configuration's simple ways to access more complex settings using ServiceStack's appSettings functionality. Let's have a look at the appSettings section of our configuration:

<appSettings>
  <add key="sqlLiteConnectionString" value="~/App_Data/db.sqlite"/>
  <add key="AdminEmailAddresses" value="darren.reid@reidsonindustries.net,kyle.hodgson@reidsonindustries.net"/>
    <add key="EmailSettings_Dev" value="{SMTPUrl:email-smtp.dev.reidsoninsdustries.net,SMTPPort:25}"/>
    <add key="EmailSettings_Test" value="{SMTPUrl:email-smtp.test.reidsoninsdustries.net,SMTPPort:25}"/>
    <add key="EmailSettings_Prod" value="{SMTPUrl:email-smtp.reidsoninsdustries.net,SMTPPort:25}"/>
    <add key="Environment" value="Dev"/>
</appSettings>

How to do It...

We are going to need a Plain Old CLR Object (POCO) to represent the e-mail settings:

public class EmailSettings
{
  public string SMTPUrl { get;set; }
  public int SMTPPort { get;set; }
}

Create a custom AppSettings class to help access specific configuration:

public class ReidsonAppSettings : AppSettings
{

public ApplicationEnvironment Environment
{
  get
  {
    return Get("Environment", ApplicationEnvironment.Dev);
  }
}

public EmailSettings EmailSettings
{
  get
  {
    var settingsName = 
       "EmailSettings_" + Environment;
    return Get<EmailSettings>(settingsName, null);
  }
}

public List<string> AdministratorEmails
{
  get
  {
    return Get("AdminEmailAddresses", new List<string>());
  }
}

  public enum ApplicationEnvironment
  {
    Dev,
    Test,
    Prod
  }
}

Create AppSettings, OrmLite Connection Factory, and the data repository objects:

public override void Configure(Container container)
{
container.RegisterAutoWired<ReidsonAppSettings>();
var appSettings = container.Resolve<ReidsonAppSettings>();
var dbFactory = new OrmLiteConnectionFactory(
    appSettings.Get("sqlLiteConnectionString","").MapHostAbsolutePath(),
    SqliteDialect.Provider);

container.Register<IDbConnectionFactory>(dbFactory);

container.RegisterAutoWiredAs
  <ReidsonMessengerDataRepository,
  IReidsonMessengerDataRepository>();
//Other configuration...
}

In the web services, we will want to access all three objects that will be provided by the Funq container. To do this, declare public properties of the same types that are registered with the IoC container within your ServiceStack web service:

public ReidsonAppSettings ApplicationSettings 
{ get; set; }
public IDbConnectionFactory DbConnectionFactory { get; set; }
public IReidsonMessengerDataRepository DataRepository { get; set; }

How it works...

The custom settings object, ReidsonAppSettings, is a wrapper for accessing values within the appSettings section of web.config. This wrapper utilizes a few of the ServiceStack appSettings helper methods that let us store more complex information than just key/value pairs.

The list of administrator user e-mails are parsed as a comma-separated list and expressed in code as List<string>. This makes storing collections of values a lot simpler both in configuration and in code. Get<Type>(key, defaultValue) requires a type, key value, and default value if the setting is null.

Objects of key/value pairs can be read by appSettings. This requires the use of JSON-like object syntax, as seen in the previous example of application settings, but from code, it is all strongly typed configuration:

<add key="EmailSettings_Dev" value="{SMTPUrl:email-smtp.dev.reidsoninsdustries.net,SMTPPort:25}"/>

public class EmailSettings
{
  public string SMTPUrl { get;set; }
  public int SMTPPort { get;set; }
}

this.Get<EmailSettings>("EmailSettings_Dev", null);

We are sharing this configuration and other objects by registering them in a few different ways using the Funq IoC container:

  • RegisterAutoWired<CustomType>();

  • Register<Type>(instance);

  • RegisterAutoWiredAs<CustomType,AsAnotherType>();

These methods of the Funq container achieve the same result, but in different ways. RegisterAutoWired<CustomType> attempts to populate the public properties on CustomType that have the same declared type as objects that have already been registered with the Funq container. In the example of ReidsonAppSettings, we don't need to pass an instance to RegisterAutoWired as the Funq container will take care of any required instantiation. The order of registration is very important when dealing with IoC—ReidsonAppSettings also doesn't have any dependencies, so we can register this first.

Next, we registered an instance of OrmLiteConnectionFactory, specifying the interface IDbConnectionFactory. Since we used the Register<AsAnotherType> method to which we passed an instance, we don't get any auto-wiring for dependencies via a constructor or via public properties. This needs to be done manually when using the Register<AsAnotherType> method.

The registration of our data repository object used the RegisterAutoWiredAs<CustomType,AsAnotherType> method that controls the construction of the object and, in this case, took care of the two public property dependencies, IDbConnectionFactory and ReidsonAppSettings, automatically.

If you want an instance of a registered type and you have access to the container, you can use the Resolve<CustomType> method.

Note

With Funq, as with any IoC, it's best practice to have control over all of your registrations and configurations in one place. As such, you want to avoid sharing the instance of the container with other classes—this will keep your code base easier to maintain.

There's more...

It is possible to use other IoC container implementations with ServiceStack with the use of custom adapters. A Ninject adapter is available on Nuget as an alternative. Otherwise, the IContainerAdapter interface is provided to create your own adapter to use with your IoC container of choice.

Latest Reviews (2 reviews total)
ServiceStack 4 Cookbook
Unlock this book and the full library FREE for 7 days
Start now