Monday, May 25, 2009

MassTransit Host & Setup


The glue that ties all of MassTransit's moving pieces has to be done  on starting you application. We need configure the service to know what to start up, how to find it and in what context to run it.

MassTransit has split the host service into a separate project, namely TopShelf. you will see TopShelf being used to set up our MassTransit programs in the entry points of our application, typically with the Program.Main(string[] args) method.

The basic set up steps for creating a runner configuration are:

  • Describe the Service
  • Instruct how the service will be run
  • Configure the the service

Once you have done this, the TopShelf Runner can host the service.

Describing the Service means give the service a name, a display name and a description. The display name and description are visible from the Service Control Manager while the service name is intend for console line interactions

Instructing how the service will be run: Define any known dependencies (MSMQ, IIS, SqlServer etc), any actions that should be performed prior to running the service/host and also how the service is to be run: i.e what credentials will the service run under. We can also use the UseWinFormHost<T> where we can supply the name of the WinForm that is the host. This is great for demos, but I am not sure if it is intended for production use... Chris and Dru may care to comment on this; either way its handy when getting to terms with the stack.

Next we need to configure the service(s) we are hosting. In here we can define some delegate for certain event in service life (WhenStarted, WhenStopped etc) and we can also weave some of our IoC voodoo majic by defining our service locator. Again the authors have decided to use Castle Windsor for the sample, however I believe you can use any of the CommonServiceLocator Containers. As this method need to returns something that implements IServiceLocator, using the DefaultMassTransitContainer type makes life a little easier as it does a fair bit of the plumbing for you including setting the current service locator to itself.

private static void Main(string[] args)
//from Starbucks.Barista.Program.Main(string[] args) - Modified for readability
var cfg = RunnerConfigurator.New(configurator =>
//Describe the Service
configurator.SetDisplayName("Starbucks Barista");
configurator.SetDescription("A Mass Transit sample service for making orders of coffee.");

//Instruct How the service will be run
configurator.BeforeStart(a => { });

//Configure the service(s)
configurator.ConfigureService<BaristaService>(serviceConfigurator =>
serviceConfigurator.CreateServiceLocator(() =>
//Use MassTransit's built in Container (Castle Windsor specific), described earlier
IWindsorContainer container = new DefaultMassTransitContainer("Starbucks.Barista.Castle.xml");

//Add the components to the container
container.AddComponent("sagaRepository", typeof(ISagaRepository<>), typeof(InMemorySagaRepository<>));

//Tracing - not super important in this context
Trace.Listeners.Add(new TextWriterTraceListener(Console.Out));
StateMachineInspector.Trace(new DrinkPreparationSaga(CombGuid.Generate()));

//Return the Current ServiceLocator, which has been assigned in the DefaultMassTransitContainer ctor
return ServiceLocator.Current;
//Define delegates (specifically service methods) to fire on given ServiceConfigurator events
serviceConfigurator.WhenStarted(baristaService => baristaService.Start());
serviceConfigurator.WhenStopped(baristaService => baristaService.Stop());
Runner.Host(cfg, args);


dru said...

The winform host is production usable, just not as a winservice. ;) You might use it to host a winform, but we mostly use it for Demos.

You are correct, you can you any container, as everything is abstracted behind the CSL.

RhysC said...

Also note that Dru has some posts on topshelf hereand here