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
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.
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.
Let's begin by creating our first service with ServiceStack.
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:

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!
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.
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.
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; } }
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; } }
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"}]}
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"} ] }
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.
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
.
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.
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:
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>
ServiceStack will need to have the file extension added to the
AllowFileExtensions
property onHostConfig()
:var hostConfig = new HostConfig(); hostConfig.AllowFileExtensions = {"dart"}; hostConfig.HandlerFactoryPath = "api"; SetConfig(hostConfig);
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(); } }
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.
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());
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.
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.
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; }
}
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.
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.
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); } }
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 caseGreeterRequest
is associated with the URL/greetings/{Name}
. The{Name}
URL binds the value in the place of the path to theName
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 addingotherway
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 ofRouteAttribute
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 asmyObjectInstance.GetType()
, which can be used on any object.
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.
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.
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.
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.
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.
First, we'll write a test that illustrates the problem we're trying to solve—that the current implementation isn't thread-safe.
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.We'll create an interface that covers the most important functionality for
StaticMessageRepository
—the method to Add new messages—and another method that acceptsPredicate<Message,bool>
and returnsIEnumerable<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 theAppHost.Configure
method, allowing us to keep control over which implementation to use in that central location.Next, we'll start wiring up the messages repository with
Funq
. We'll set up our productionAppHost
class to wire up our existing but flawedStaticMessagesRepository
, but we'll start working on a new implementation that leverages OrmLite. In our tests, we'll test the newOrmMessagesRepository
until it solves the problem and is working. When we're through, we can simply change theAppHost.Configure
method in our productionAppHost
class to use the newly tested implementation.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.
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.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 havingList<Message>
as a field onMessengerService
, we'll wrap it in a class, and then use this new class for access. This class will implement anIMessageRepository
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(); } }
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 changeMessengerService
to rely on Funq to provideIMessageRepository
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() }; } }
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()
requiresExpression<Func<Message,bool>>
and not justFunc<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.
Next, let's go into
TestFixtureSetUp
and wire up our new dependency. We'll also add code to aSetUp
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 toAppHost
:[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>(); } }
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 changeMessengerService
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() }; }
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.Again, we'll start with a test to prove our theory that
BasicOrmMessageRepository
isn't fast enough. We'll createTestFixtureSetup
that configuresBasicAppHost
to wire upBasicOrmMessageRepository
and aSetup
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.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 requiresExpression<Func<Message,Bool>>
, and right now we only accept aFunc<Message,Bool>
function. Let's start by refactoring the interface and the basic static list, then refactoringBasicOrmMessageRepository
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(); } }
Now that we've changed the method signature on the interface and updated our
StaticMessageRepository
implementation, we need to updateBasicOrmMessageRepository
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); } } }
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 productionAppHost
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>(); } } }
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.
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
.
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>
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; }
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.
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.