DEV Community

Tony Morris
Tony Morris

Posted on

ServiceStack in a Console Application

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.cs

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();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

DependencyConfig.cs

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 dbFactory = new OrmLiteConnectionFactory(settings.Get("ConnectionString", "default connection string"), new OracleOrmLiteDialectProvider(false, false, OracleOrmLiteDialectProvider.ManagedProvider));
                return dbFactory;
            });

            Program.Container.Register<IWorkRepository>(x => new WorkRepository(x.Resolve<IAppSettings>(), x.Resolve<IDbConnectionFactory>()));
            Program.Container.Register<IWorkManager>(x => new WorkManager(x.Resolve<IWorkRepository>()));
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Worker.cs

namespace ServiceStack.Console
{
    public class Worker
    {
        private readonly IWorkManager manager;

        public Worker(IWorkManager manager)
        {
            this.manager = manager;
        }

        public void Work()
        {
            this.manager.DoWork();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

IWorkManager.cs

namespace ServiceStack.Console.Interfaces
{
    public interface IWorkManager
    {
        void DoWork();
    }
}
Enter fullscreen mode Exit fullscreen mode

WorkManager.cs

namespace ServiceStack.Console
{
    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
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

IWorkRepository.cs

namespace ServiceStack.Console.Interface
{
    public interface IWorkRepository
    {
        object GetData();
    }
}
Enter fullscreen mode Exit fullscreen mode

WorkRepository.cs

namespace ServiceStack.Console
{
    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
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

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).

Another point to note is the use of the IDbConnectionFactory interface to access the database. This allows us to use an in-memory database easily in tests, such as Sqlite, in order to validate the hard-to-test data access classes.

I Love The 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. In fact, I even blogged about it. 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.

ConfigKeys.cs

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);
    }
}
Enter fullscreen mode Exit fullscreen mode

ConfigValues.cs

namespace ServiceStack.Console
{
    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";
    }
}
Enter fullscreen mode Exit fullscreen mode

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.

Wrap It 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.

Top comments (1)

Collapse
 
djnitehawk profile image
Dĵ ΝιΓΞΗΛψΚ • Edited

servicestack would've been a godsend if we didn't have to pay for it :-(
but i do love it and have converted all of my projects to ss.
asp.net mvc/web-api is dead to me ;-)