I absolutely love ServiceStack. Let’s get that out into the open. With every new project I begin, my first question is “How can I use ServiceStack here?”
My typical reasoning for using ServiceStack is to utilize its amazing web service framework. I could extoll its message-based design and extensibility for pages upon pages.
When I’m working on an ASP.NET MVC web application, I still pull in ServiceStack to get its additional MVC features. This allows me to use the built-in ServiceStack components (e.g., Session, Caching, Authentication, etc.) on top of my favorite web application framework.
However, due to the nature of my job, I am working on console applications that must be run from the Windows Task Scheduler with some regularity. While ServiceStack hooks nicely into the HTTP-based frameworks of web services and web applications, there doesn’t appear to be much utility for it within a pure console application.
This is mostly true if you think of ServiceStack as just a web framework. I
personally like to think of ServiceStack as both a web framework and a
collection of tools that I think I would build in another life. These tools
include the built-in Funq IoC container and the AppSettings
abstraction.
Examples below on how I’m doing this with a real project.
Using Funq
Funq is ServiceStack’s built-in IoC container. Other amazing IoC containers exist (I personally love Autofac, but I like that this one is built in.
In a typical web application, the Funq container is created correctly at each scope and managed by ServiceStack. In a console application, this level of integration doesn’t work, so instead I hack around it by creating a static container that is available to the entire application. This smells like the Service Locator pattern, but we don’t go down that route by convention. Note that there is nothing technically from stopping a developer from calling the container directly rather than utilizing constructor injection, but we yell at developers who do this.
The code below shows a sample console application that has a static Container
that is utilized by the DependencyConfig
class. From there, each
implementation of an interface utilizes constructor injection to get the
implementation of the dependencies.
Program Setup
The following code sample is the main entrypoint of a sample console
application. You’ll see that it contains the static readonly Container
instance, which DependencyConfig.Setup()
actually updates (seen later).
You then can see how the Container
is accessed when instantiating a new
Worker
instance. This is the only use-case of accessing the Container
directly from code (similar to the Service Locator pattern).
namespace ServiceStack.Console
{
static class Program
{
public static readonly Container Container = new Container();
static void Main(string[] args)
{
DependencyConfig.Setup();
new LogConfig(Container.Resolve<IAppSettings>()).Setup();
var worker = new Worker(Container.Resolve<IWorkManager>());
worker.Work();
}
}
}
Dependency Setup
Utilizing ServiceStack’s specific flavor of Funq, you’ll see that I use the
Container.RegisterAutoWiredAs<T, TAs>
extension method. This is shorthand for
the Container.Register<T>(...)
methods, allowing this dependency container
setup to be straightforward and easy to update.
namespace ServiceStack.Console
{
public static class DependencyConfig
{
public static void Setup()
{
Program.Container.Register<IAppSettings>(x => new AppSettings());
Program.Container.Register<IDbConnectionFactory>(x =>
{
var settings = x.Resolve<IAppSettings>();
var connectionString = settings.Get("ConnectionString", "default");
var provider = new OracleOrmLiteDialectProvider();
var dbFactory = new OrmLiteConnectionFactory(connectionString, provider);
return dbFactory;
});
Program.Container.RegisterAutoWiredAs<WorkRepository, IWorkRepository>();
Program.Container.RegisterAutoWiredAs<WorkManager, IWorkManager>();
}
}
}
The Worker
This is a very simple class that has a constructor-injected dependency of
IWorkManager
(which is resolved from the Program
class above).
namespace ServiceStack.Console
{
public class Worker
{
private readonly IWorkManager manager;
public Worker(IWorkManager manager)
{
this.manager = manager;
}
public void Work()
{
this.manager.DoWork();
}
}
}
Work Manager
The code below contains the interface IWorkManager
, and then a concrete
implementation of the interface in WorkManager
. The WorkManager
implementation contains another constructor-injected dependency in
IWorkRepository
. This dependency is resolved via Program
-level Container
object during the resolution of the IWorkManager
initially.
namespace ServiceStack.Console.Interfaces
{
public interface IWorkManager
{
void DoWork();
}
public class WorkManager : IWorkManager
{
private readonly IWorkRepository repository;
public WorkManager(IWorkRepository repository)
{
this.repository = repository;
}
public void DoWork()
{
var data = this.repository.GetData();
DoTheThing(data);
}
private void DoTheThing(object data)
{
// Data
}
}
}
Work Repository
The IWorkRepository
interface below merely returns data from the GetData()
method. The concrete implementation, WorkRepository
, utilizes ServiceStack’s
IDbConnectionFactory
interface to inject data access dependencies without
needing to know where it’s connecting. This is especially useful when testing
data access, as it is trivial to mock out with a database like Sqlite.
namespace ServiceStack.Console.Interface
{
public interface IWorkRepository
{
object GetData();
}
public class WorkRepository : IWorkRepository
{
private readonly IAppSettings settings;
private readonly IDbConnectionFactory connectionFactory;
public WorkRepository(IAppSettings settings, IDbConnectionFactory connectionFactory)
{
this.settings = settings;
this.connectionFactory = connectionFactory;
}
public object GetData()
{
using (var connection = this.connectionFactory.OpenDbConnection())
{
// Get and return data
}
}
}
}
This type of application architecture assures a straightforward unit test plan, as each concrete implementation can be tested in isolation by utilizing mock objects (I like to use Moq for this).
AppSettings Abstraction
I have personally written a strongly-typed configuration abstraction to mirror
what is in my web.config
or app.config
at least a dozen times. I am done
with writing that type of tight coupling, as it makes updates a bit too
cumbersome.
As a replacement, I now keep a class with the <appSettings />
keys defined, as
well as a class with the default values for each of those keys.
namespace ServiceStack.Console
{
public static class ConfigKeys
{
public static readonly string ApiKey = nameof(ApiKey);
public static readonly string ApplicationName = nameof(ApplicationName);
public static readonly string ApplicationVersion = nameof(ApplicationVersion);
public static readonly string Environment = nameof(Environment);
}
public static class ConfigValues
{
public static readonly string DefaultApiKey = "abcd1234";
public static readonly string DefaultApplicationName = "ServiceStack Console Test Application";
public static readonly string DefaultApplicationVersion = "1.0.0";
public static readonly string DefaultEnvironment = "Local";
}
}
Using constructor injection and Funq from above, I then pull the data out of the
IAppSettings
instance by using its IAppSettings.Get<T>(string name, T
defaultValue)
method. A good example of this is when I retrieve the
"ConnectionString"
value in the DependencyConfig
class above.
Wrapping It All Up
Nothing I typed above is dependent on ServiceStack. I can pull in Autofac and
use any of the myriad of web.config
or app.config
abstraction libraries (or
roll my own), and the code will work precisely the same. However, due to my
experience level with ServiceStack (and its ease of use, if we’re being honest),
I tend to use what I know. In this case, it means pulling in a web framework to
utilize its IoC container and application configuration abstraction.