Book Image

ServiceStack 4 Cookbook

Book Image

ServiceStack 4 Cookbook

Overview of this book

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

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="[email protected],[email protected]"/>
    <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.