Friday, September 28, 2012

Parsing a Connection String With Sprache

Sprache is a very cool lightweight parser library for C#. Today I was experimenting with parsing EasyNetQ connection strings, so I thought I’d have a go at getting Sprache to do it. An EasyNetQ connection string is a list of key-value pairs like this:

key1=value1;key2=value2;key3=value3

The motivation for looking at something more sophisticated than simply chopping strings based on delimiters, is that I’m thinking of having more complex values that would themselves need parsing. But that’s for the future, today I’m just going to parse a simple connection string where the values can be strings or numbers (ushort to be exact).

So, I want to parse a connection string that looks like this:

virtualHost=Copa;username=Copa;host=192.168.1.1;password=abc_xyz;port=12345;requestedHeartbeat=3

… into a strongly typed structure like this:

public class ConnectionConfiguration : IConnectionConfiguration
{
public string Host { get; set; }
public ushort Port { get; set; }
public string VirtualHost { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public ushort RequestedHeartbeat { get; set; }
}

I want it to be as easy as possible to add new connection string items.

First let’s define a name for a function that updates a ConnectionConfiguration. A uncommonly used version of the ‘using’ statement allows us to give a short name to a complex type:

using UpdateConfiguration = Func<ConnectionConfiguration, ConnectionConfiguration>;

Now lets define a little function that creates a Sprache parser for a key value pair. We supply the key and a parser for the value and get back a parser that can update the ConnectionConfiguration.

public static Parser<UpdateConfiguration> BuildKeyValueParser<T>(
string keyName,
Parser<T> valueParser,
Expression<Func<ConnectionConfiguration, T>> getter)
{
return
from key in Parse.String(keyName).Token()
from separator in Parse.Char('=')
from value in valueParser
select (Func<ConnectionConfiguration, ConnectionConfiguration>)(c =>
{
CreateSetter(getter)(c, value);
return c;
});
}

The CreateSetter is a little function that turns a property expression (like x => x.Name) into an Action<TTarget, TProperty>.

Next let’s define parsers for string and number values:

public static Parser<string> Text = Parse.CharExcept(';').Many().Text();
public static Parser<ushort> Number = Parse.Number.Select(ushort.Parse);

Now we can chain a series of BuildKeyValueParser invocations and Or them together so that we can parse any of our expected key-values:

public static Parser<UpdateConfiguration> Part = new List<Parser<UpdateConfiguration>>
{
BuildKeyValueParser("host", Text, c => c.Host),
BuildKeyValueParser("port", Number, c => c.Port),
BuildKeyValueParser("virtualHost", Text, c => c.VirtualHost),
BuildKeyValueParser("requestedHeartbeat", Number, c => c.RequestedHeartbeat),
BuildKeyValueParser("username", Text, c => c.UserName),
BuildKeyValueParser("password", Text, c => c.Password),
}.Aggregate((a, b) => a.Or(b));

Each invocation of BuildKeyValueParser defines an expected key-value pair of our connection string. We just give the key name, the parser that understands the value, and the property on ConnectionConfiguration that we want to update. In effect we’ve defined a little DSL for connection strings. If I want to add a new connection string value, I simply add a new property to ConnectionConfiguration and a single line to the above code.

Now lets define a parser for the entire string, by saying that we’ll parse any number of key-value parts:

public static Parser<IEnumerable<UpdateConfiguration>> ConnectionStringBuilder =
from first in Part
from rest in Parse.Char(';').Then(_ => Part).Many()
select Cons(first, rest);

All we have to do now is parse the connection string and apply the chain of update functions to a ConnectionConfiguration instance:

public IConnectionConfiguration Parse(string connectionString)
{
var updater = ConnectionStringGrammar.ConnectionStringBuilder.Parse(connectionString);
return updater.Aggregate(new ConnectionConfiguration(), (current, updateFunction) => updateFunction(current));
}

We get lots of nice things out of the box with Sprache, one of the best is the excellent error messages:

Parsing failure: unexpected 'x'; expected host or port or virtualHost or requestedHeartbeat or username or password (Line 1, Column 1).

Sprache is really nice for this kind of task. I’d recommend checking it out.

Tuesday, September 25, 2012

Replacing EasyNetQ Components

EasyNetQ, my simple .NET API for RabbitMQ, is a library composed of small components. Until today, the code simply wired the components in a messy hard-coded routine. Now it has its own tiny internal IoC container.  When you write:
var bus = RabbitHutch.CreateBus("host=localhost");

... the static method CreateBus registers the components with the container and then resolves the IBus instance. The really cool thing about this is that it allows you, the user, to replace any of the internal components, including IBus, with your own implementations. An overload of the CreateBus method provides the hook which gives you access to the component registration. The signature looks like this:
public static IBus CreateBus(string connectionString, Action<IServiceRegister> registerServices)

The IServiceRegister interface provides a single method:
public interface IServiceRegister
{
    IServiceRegister Register<TService>(Func<IServiceProvider, TService> serviceCreator) where TService : class;
}

So to register your own logger, based on IEasyNetQLogger, you'd write this code:
var logger = new MyLogger(); // MyLogger implements IEasyNetQLogger
var bus = RabbitHutch.CreateBus(connectionString, 
    serviceRegister => serviceRegister.Register(serviceProvider => logger));

The Register method's argument, Func<IServiceProvider, TService>, is a function that's run when CreateBus pulls together the components to make an IBus instance. IServiceProvider looks like this:
public interface IServiceProvider
{
    TService Resolve<TService>() where TService : class;
}

This allows you to access other services that EasyNetQ provides. If for example you wanted to replace the default serializer with your own implementation of ISerializer, and you wanted to construct it with a reference to the internal logger, you could do this:
var bus = RabbitHutch.CreateBus(connectionString, serviceRegister => serviceRegister.Register(
    serviceProvider => new MySerializer(serviceProvider.Resolve<IEasyNetQLogger>())));

There’s nothing to stop you registering your own interfaces with the container that you can then use with your implementations of EasyNetQ’s service interfaces.
To see the complete list of components that make up the IBus instance, and how they are assembled, take a look at the ComponentRegistration class.

Friday, September 14, 2012

Return a Task From BeginExecuteNonQuery

Blog as notepad time. Just a little reminder for myself on how to return the result from BeginExecuteNonQuery as a Task<int>

public Task<int> Save(string value)
{
var taskCompletionSource = new TaskCompletionSource<int>();

var connection = new SqlConnection(connectionString);
connection.Open();
var command = new SqlCommand("uspSaveSomeValue", connection)
{
CommandType = CommandType.StoredProcedure
};
command.Parameters.AddWithValue("@myparam", value);
command.BeginExecuteNonQuery(asyncResult =>
{
var result = command.EndExecuteNonQuery(asyncResult);
command.Dispose();
connection.Dispose();
taskCompletionSource.SetResult(result);
}, null);

return taskCompletionSource.Task;
}

If you know a better way, please comment below.

Yes, yes, I know, but I’m not working on 4.5 yet  :(

Update: Ken Egozi suggested using Task<int>.Factory.FromAsync. Of course! I’d been doing so much TaskCompletionSource manual task creation recently that I’d forgotten about this useful shortcut. Here’s a more succinct version using FromAsync:

public Task<int> Save(string value)
{
var connection = new SqlConnection(connectionString);
connection.Open();
var command = new SqlCommand("uspSaveSomeValue", connection)
{
CommandType = CommandType.StoredProcedure
};
command.Parameters.AddWithValue("@myparam", value);

return Task<int>.Factory.FromAsync(command.BeginExecuteNonQuery(), asyncResult =>
{
var result = command.EndExecuteNonQuery(asyncResult);
command.Dispose();
connection.Dispose();
return result;
});
}

Thursday, September 13, 2012

Wiring up TopShelf, Windsor and EasyNetQ

EasyNetQ is my simple to use .NET API for the awesome RabbitMQ messaging broker. Architecting system around a message bus involves writing many small focussed components that sit on the bus waiting for messages they care about to arrive. These are best implemented as Windows services. My favourite way of implementing Windows services is to use TopShelf. This very nice open source library grew out of the excellent MassTransit project. It makes writing windows services super easy; you simply create a console project, “install-package Topshelf”, and use the neat fluent API to describe your service. An IoC container should be at the heart of any but the simplest .NET application. If you’ve not used an IoC container before I talked about why you should several years ago. There are quite a few IoC containers to choose from, my weapon of choice is Castle Windsor.

In this post I want to show how I wire up TopShelf, Windsor and EasyNetQ.

The Zen of IoC says that any application that uses an IoC container should reference it in only two places. First to create an instance of the container that lasts the lifetime of the application. Second to resolve a root service from the container. All the other dependencies are supplied invisibly by the container itself. This magic is what makes IoC containers such awesome and essential frameworks. Following this rule, in the Main() function we create the IoC container and resolve the root service of our application, in this case IVaultService, all within the fluent API provided by TopShelf.

public class Program
{
public static void Main(string[] args)
{
// create the container and run any installers in this assembly
var container = new WindsorContainer().Install(FromAssembly.This());
// start of the TopShelf configuration
HostFactory.Run(x =>
{
x.Service<IVaultService>(s =>
{
// resolve the root IVaultService service
s.ConstructUsing(name => container.Resolve<IVaultService>());
s.WhenStarted(tc => tc.Start());
s.WhenStopped(tc =>
{
tc.Stop();
// with Windsor you must _always_ release any components that you resolve.
container.Release(tc);
// make sure the container is disposed
container.Dispose();
});
});

x.RunAsLocalSystem();

x.SetDescription("Vault service.");
x.SetDisplayName("My.Vault.Service");
x.SetServiceName("My.Vault.Service");
});
}
}

A cardinal rule of Windsor is that you must release any components that you resolve. Windsor tracks any components that implement IDisposable and ensures that Dispose is called no matter where the component gets resolved in the dependency graph, but you need to call Release for this to happen correctly. The ‘tc’ variable is the instance of IVaultService that gets resolved in the ‘ConstructUsing’ call, so we can use it in the Release call.

What about EasyNetQ? The Zen of EasyNetQ says that you should create a single instance of IBus that lasts the lifetime of the application. Now we could have created our IBus instance in Main() alongside the TopShelf setup and newing up the container, but since we’ve got a container we want it to manage the lifetimes of all the components used in the application. First let’s create a simple factory method that gets the connection string for EasyNetQ and creates a new instance of IBus:

public class BusBuilder
{
public static IBus CreateMessageBus()
{
var connectionString = ConfigurationManager.ConnectionStrings["easynetq"];
if (connectionString == null || connectionString.ConnectionString == string.Empty)
{
throw new VaultServiceException("easynetq connection string is missing or empty");
}

return RabbitHutch.CreateBus(connectionString.ConnectionString);
}
}

Now we can write our IWindsorInstaller to register our services:

public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IVaultService>().ImplementedBy<VaultService>().LifestyleTransient(),
Component.For<IBus>().UsingFactoryMethod(BusBuilder.CreateMessageBus).LifestyleSingleton()
);
}
}

Note that we tell Windsor to create our IBus instance using our factory with ‘UsingFactoryMethod’ rather than ‘Instance’. The Instance method tells Windsor that we will take responsibility for the lifetime of the service, but we want Windsor to call Dispose when the application shuts down, UsingFactoryMethod tells Windsor that it needs to manage the IBus lifestyle. We declare it as ‘LifestyleSingleton’ because we only want a single instance of IBus for the entire lifetime of the application.

Now we can reference IBus in our IVaultService implementation:

public interface IVaultService
{
void Start();
void Stop();
}

public class VaultService : IVaultService
{
private readonly IBus bus;
public VaultService(IBus bus)
{
this.bus = bus;
}

public void Start()
{
bus.SubscribeAsync<MyMessage>("vault_handler", msg =>
{
// handle the message here
});
}

public void Stop()
{
// any shutdown code needed
}
}

Here we are simply subscribing to MyMessage in the Start method of VaultService. I would probably also have an IMyMessageHandler service referenced by IVaultService to do the message handling itself.

So there you have it, a simple recipe for using these three excellent OSS projects together. As a side note it’s worth pointing out that they play together without depending on each other directly. I think this is the way to go with OSS components; they should provide points that allow you to plug in other pieces without mandating them.