jason

Jason is a small and simple infrastructure framework that aims to solve the commanding portion of CQRS giving to the developer a powerful infrastructure to introduce the command paradigm in the solution.

Jason is composed of two main parts the server components and the client components.

On the server side Jason can be hosted as a WCF service or as a MVC WebAPI controller, thus the client can encompass from Silverlight clients to “Json” clients, such as a HTML/JQuery application, passing through all the .net application types you can think of that can issue a HTTP request using SOAP, Json or bare Xml.

Why commanding is so important?

Little digression…

moving from an RPC (Remote Procedure Call) model, like the one proposed out-of-the-box by WCF (please notice the out-of-the-box meaning that is the default approach proposed, not the only one) to a request/response model (or command based model) allows the developer to easily define the bounds of each context and allows the developer to express much more strongly the intention of each action.

The other important consideration is that I am speaking about the client –> server communication direction where the client is asking the server to do something, for the server –> client, e.g. when the client queries the server to read data, the standard WCF approach, or any other server technology that you can think of, to expose the read model is really a valid solution.

Client side point of view

First of all let’s have a look at how stuff works with Jason from the client side point of view:

var factory = new DefaultWorkerServiceClientFactory();
using( var client = factory.CreateAsyncClient() )
{
var task = client.ExecuteAsync( new PocoCommand() )
.ContinueWith( r =>
{
var e = r.Result as PocoCommandResponse;
} );

task.Wait();
}

Trivial, isn’t it?

  • we create a service client factory;
  • we use the factory to create an async (task based, thus awaitable) client;
  • issue a request to execute a command, that is a completely POCO class;
  • if we need we can wait for a response, that as the command can be a POCO class;

Wait a minute…

Why the hell the DataContractSerializer does not complain about the unknown classes? if you are a long time WCF user you certainly know that every single type that we try to pass through the wire must be a well known type to the DataContractSerializer, and by default the serializer utilizes the service interface definition to determine which are the known types.

A little lie

In the above snippet a omitted the Jason configuration setup:

var config = new DefaultJasonClientConfiguration( AppDomain.CurrentDomain.BaseDirectory, factory )
{
CommandsSelector = t =>
{
return t.IsAttributeDefined<DataContractAttribute>()
&& ( t.Name.EndsWith( "Command" ) || t.Name.EndsWith( "CommandResponse" ) );
}
};

config.Initialize();

  • we create a default Jason configuration bound to:
    • a crawling directory that will be scanned looking for Jason types (more on this later);
    • a client factory needed to support known types changes at runtime;
  • we use a delegate to express which types, POCO types, must be treated as commands and thus must “meet” the DataContractSerializer;
  • in the end we initialize the configuration once, and only once;

Server side point of view

From the server side point of view all you need to do is to define an handler for your command:

class PocoCommandHandler : AbstractCommandHandler<PocoCommand>
{
protected override Object OnExecute( PocoCommand command )
{
return new PocoCommandResponse();
}
}

That’s it, the infrastructure (that as you may wonder must be configured) handles all the details for us and in the end calls the handler of the command. Inheriting from AbstractCommandHandler<TCommand> is not a requirement, simply saves us from some boiler plate code that ICommandHandler<TCommand> interface requires.

Server side configuration

Configuration, server side, starts from the assumption that we are using an Inversion of Control container (such as Castle Windsor) so the first thing to do is to register Jason required types into the container itself:

var windsor = new WindsorContainer();

windsor.Register( Component.For<IServiceProvider>().Instance( windsor ) );
windsor.Register( Component.For<ICommandHandlersProvider>().ImplementedBy<DefaultCommandHandlersProvider>() );

/*
* the WorkerService is required only if we want to host Jason using WCF
* so also the IJobHandlersProvider and IJobTaskHandlersProvider
*/
windsor.Register( Component.For<IJobHandlersProvider>().ImplementedBy<DefaultJobHandlersProvider>() );
windsor.Register( Component.For<IJobTaskHandlersProvider>().ImplementedBy<DefaultJobTaskHandlersProvider>() );

windsor.Register( Component.For<IWorkerService>().ImplementedBy<WorkerService>() );

Let’s start from the simple stuff: WebAPI; in order to host Jason in a MVC WebAPI controller all we have to do is:

  • Add a new ApiController to the solution;
  • Make the controller depend on the ICommandHandlersProvider Jason type;
public class JasonController : ApiController
{
readonly ICommandHandlersProvider handlerProvider;

public JasonController( ICommandHandlersProvider handlerProvider )
{
this.handlerProvider = handlerProvider;
}

public HttpResponseMessage Post( Object command )
{
var handler = this.handlerProvider.GetHandlerFor( command );
var result = handler.Execute( command );

return Request.CreateResponse( HttpStatusCode.OK, result );
}
}

As for the client in order to have everything up & running we have to configure Jason:

var jasonConfig = new DefaultJasonServerConfiguration( Path.Combine( AppDomain.CurrentDomain.BaseDirectory, "bin" ) )
{
RegisterAsTransient = ( c, i ) =>
{
this.windsor.Register
(
Component.For( c )
.ImplementedBy( i )
.LifeStyle.Is( Castle.Core.LifestyleType.Transient )
);
},
CommandsSelector = t =>
{
return t.IsAttributeDefined<DataContractAttribute>()
&& ( t.Name.EndsWith( "Command" ) || t.Name.EndsWith( "CommandResponse" ) );
}
};

jasonConfig.Initialize();

The configuration is really similar, except that we also provide a way for the configuration engine to use our own Inversion of Control container to register stuff required by Jason internally.

.m