Getting started with MassTransit

Ok so I continue to play with MassTransit and I really like it. Unfortunately I still think there is a small barrier to entry that is stopping people from using it. The guys who have written it have done a great job of building an easy to use stack, but as it grows it may feel a bit like you don’t know where to start.What I aim to do here is break the whole thing down to easy to understand pieces (theory) and then get the pieces together (practice!)

MassTransit leans on the concept of Publish/Subscribe or Pub/Sub. The idea being I can raise an event by sending a message (publishing) and any number of consumers that are interested in that message can listen in and consume that message (subscribing). This means as new subscriber become known the publisher itself does not have to be aware of its existence, the Bus (MT) will deal with it, providing a nice sense of loose coupling.

An example could be a new person starts at your place of work. His new boss goes in to the HR system and creates a new employee request*. This goes off to HR where it is actioned and a new Employee notification* is made. A slew of process are now kickoff that HR has no idea about , nor do they care. These could include the new employees desk set up, Identification preparation, security clearance checks, various inductions bookings… who knows? If a department or application are interested in that message they just subscribe to it.

*These are the potential published message

Right, lets delve in to the specifics:

Messages

Consumers/Subscribers

Publishers

EndPoints

Host & Set up

Sagas

 

 

For background on MassTransit see my previous intro post here and some here

PowerShell to set up MSMQ private queues for MassTransit

A pretty self explanatory title: I want to be able to create MSMQ private queues on the fly. I am currently playing with Mass Transit 0.6 and there are a couple of queues i needed to create and would like them to be done upfront. As far as i am aware there you have to go into the config of each project and get the names of each queue and manually create them. This script means i don’t have to (I switch machines a lot):

CAVEAT: I am not a PS guru, in fact i am a complete n00b, combine that with my 101 knowledge of MSMQ and this is probably a disaster; you have been warned.


#Beginning of MassTransitSetup.ps1#
param(
[string] $nameofQ, [string]$username
)
[void][System.Reflection.Assembly]::LoadWithPartialName("System.Messaging")

function CreatePrivateMSMQQueue {
param ( [string]$queuename = $(throw "Please specify the queue name!"),
[string]$user)

if ([System.Messaging.MessageQueue]::Exists($queuename))
{
write-host "$queuename already exists"
}
else
{
$newQueue = [System.Messaging.MessageQueue]::Create($queuename)
if ([System.Messaging.MessageQueue]::Exists($queuename))
{
write-host "$queuename has been created"
$newQueue.Label = $queuename
#Default to everyone if no user is specified
if([string]::IsNullOrEmpty($user)){$user = "Everyone"}
write-host "Setting permissions for user : $user"
$newQueue.SetPermissions(
$user,
[System.Messaging.MessageQueueAccessRights] "ReceiveMessage, PeekMessage, GetQueueProperties, GetQueuePermissions")
}
else
{
write-host "$queuename could not be created!!!"
}
}
}

function CreateDefaultMassTransitQueues{
param ( [string]$user)

$deaultqueues = ".\private$\mt_client", ".\private$\mt_server", ".\private$\mt_server1", ".\private$\mt_subscriptions"
foreach($i in $deaultqueues)
{
CreatePrivateMSMQQueue $i $user
}
}

#Begining of script
if([string]::IsNullOrEmpty($nameofQ))
{
CreateDefaultMassTransitQueues $username
}
else
{
CreatePrivateMSMQQueue $nameofQ $username
}

For more info on MassTransit see the google code home page and be sure to check out the wiki on how to set up the starbucks sample. If you are running the starbucks sample set the queues in the scripts above to:


$deaultqueues = ".\private$\mt_client",
".\private$\mt_server",
".\private$\mt_server1",
".\private$\mt_subscriptions",
".\private$\mt_subscription_ui",
".\private$\mt_health",
".\private$\mt_timeout"

MassTransit : Classic WebForms

The Web sample in the MassTransit download that i talked about in the last post used MonoRail. As i am working on a project not using monorail (and there may be a couple of others doing the same) i thought i would make demo project using asp.net, oldskool.

The project contains 6 files (well 9 really)
AsynchWebForm.aspx (marked as Async=”true”)
Global.asax
Web.config
WebAppContainer.cs
RequestMessage.cs
ResponseMessage.cs

Thats it. It references the mass transit dlls (mt.sb., mt.sb.msmq, mt.WindsorInt) and the appropriate castle dlls.
the global.asax is just like the DashboardApplication in the morails sample and the WebAppContainer.cs again is similar to the monorail sample without any references to monorail! The message are exactly the same and the web config has the castle section definition and castle section inserted into a default web.config file.
I was lazy with my resolving of the IServiceBus, see below.
—–WebApContainer——–


using System;
using Castle.Core.Resource;
using Castle.Facilities.Startable;
using Castle.MicroKernel.Registration;
using Castle.Windsor.Configuration.Interpreters;
using MassTransit.WindsorIntegration;
using MassTransit.ServiceBus;

namespace MassTransitWebTest
{
public class WebAppContainer :
DefaultMassTransitContainer
{
private static IServiceBus bus;
public WebAppContainer()
: base(new XmlInterpreter(new ConfigResource()))
{
RegisterFacilities();
bus = Resolve();
}

protected void RegisterFacilities()
{
AddFacility("startable", new StartableFacility());
}

internal static IServiceBus getBus()//yes im that lazy
{
return bus;
}
}
}

—–AsynchWebForm.aspx.cs——–


using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using MassTransitWebTest.Server;
using MassTransit.ServiceBus;

namespace MassTransitWebTest
{
public partial class AsynchWebForm : Page, Consumes.For
{

private IServiceBus _bus;
private Guid _correlationId;
private ServiceBusRequest _request;
private ResponseMessage msg;
private RequestMessage pendingMessage;

protected void Page_Load(object sender, EventArgs e)
{
//not much to do here
}

IAsyncResult PageBeginEventHandler(object sender, EventArgs e, AsyncCallback cb, object state)
{
_request = _bus.Request()
.From(this)
.WithCallback(cb, state);

_request.Send(pendingMessage);
pendingMessage = null;

return _request;
}

void PageEndEventHandler(IAsyncResult ar)
{
IAsyncResult r = ar;
this.txtResponse.Text = msg.Text + " (and my response)";

}

#region All Members

public void Consume(ResponseMessage message)
{
msg = message;
_request.Complete();
}

#endregion

#region CorrelatedBy Members

public Guid CorrelationId
{
get { return _correlationId; }
}

#endregion

protected void Button1_Click(object sender, EventArgs e)
{
AddOnPreRenderCompleteAsync(
new BeginEventHandler(PageBeginEventHandler),
new EndEventHandler(PageEndEventHandler));
_bus = WebAppContainer.getBus();

pendingMessage = new RequestMessage(CorrelationId, this.txtRequest.Text);
}

}
}

Happy days! I am sure you can work out the rest, if any one cares the complete solution can be downloaded from :
http://www.fullstack.co.uk/downloads/MassTransitWebTest.zip
NB:See previous post for setting up queues

Mass Transit – lite weight ESB

A demo project i am frantically working on has a requirement for some sort of ESB like message control. My first instinct was to go with NServiceBus but something, for some reason drew me to MassTransit.
MassTransit is an Open source .Net project run by Chris Patterson and Dru Sellars which aims to be a “lean service bus implementation for building loosely coupled applications using the .NET framework.”. Cool cause that’s what I need.
It sit on top of MSMQ and has some heavy hooks into the castle project for DI etc.
I am writing this while i wait for my VS2008 SP1 install to finish… what the hell is it that thing?? oh the entity framework! well at least its worth the wait ;P

Anyway the documentation is a bit slight and i am a documentation nerd. I like to get a synopsis of what we are trying to achieve and some sample project, also documented, to help me get up to speed, so here is my very basic version of just getting started.

You can just download the binaries if you are feeling very confident or alternatively you can get the source which includes some sample projects.

Running the MassTransit samples:
NB: you will need to install/set up MSMQ (or whatever queue they support in the future), for details on how to do this, see below.
1) Download the source code to an appropriate folder using the following svn command (this is read only)
svn checkout http://masstransit.googlecode.com/svn/trunk/ masstransit-read-only

2) For Mass Transit you will need to create a private MSMQ queue of the name “test_servicebus” and leave the default setting of NOT transactional.

3) Open up the WebRequestReply.sln found in :
..\masstransit-read-only\Samples\WebRequestReply\WebRequestReply.sln (or 2008 if you have it)

4) Build the solution, ensuring it builds (I had to delete a couple of version files for both 2005 and 2008)

5) Set the monorail project to the start up project.

6) F5 that mutha.

This will show a splash screen that links to the asynch screen. Type in some stuff in the request textbox and hit the button and the response will come up.

Things to look for in the code:
The monorail project is the initiating code here and basically is the stuff you will be looking at for how to use this framework. If you are not familiar with castle, monorail and asynch calls then your head may pop.

Firstly look at the DashboardApplication.cs file. This is the gloabal.asax code behind file that is called on app start up. This file starts up the Container which loads the facilities/components using windsor IoC. The container inherits from the defaultMasstransitContainer which has Windsor Castle hooks. Check out the config to see the injection of the Uri and queue type for the bus.
In the DashboardApplication you should also see the line

container.Resolve().Subscribe(HandleRequestMessage);

and its related delegate

private static void HandleRequestMessage(IMessageContext ctx)
{
ResponseMessage response = new ResponseMessage(ctx.Message.CorrelationId, “Request: ” + ctx.Message.Text);

container.Resolve().Publish(response);
}

this is saying that this delegate wants to handle the receipt of the RequestMessage, “when the RequestMessage is published i want to process it with this command”.
alrighty… next is the DemoController.

This is the controller for the asych page that does the work. If you are not familiar with monorail or the ASP.net MVC project this may be a bit confusing, but this is like the code behind page for a dynamic web page. Some of the important things to note are:

Consumes.For

This says that this class is interested in (consumes or subscribes to) ResponseMessages. Now i need to look more into the .For aspect so i wont comment much yet ( i assume it related to the request message id?)
The Synch method is empty but you will notice there is a BeginAsynch method with the same signature and an EndSynch method with no signatures. These methods and there contents are the asynch approach used by Monorail. Don’t be too concerned, classic Asp.Net has had this little known feature for years albeit a slightly different syntax and wrapped around the pre-render aspect of the page life cycle (i may cover this in another post).
The asynch method is called from the the view on clicking the submit button (read up on MVC if this appears odd) where the bus is called and a Requestmessage sent to the bus. Some of the semantics here are very much monorail so the main point is:
a Request Message was sent to the Bus to be processed in an asynch fashion.
If you have debugging on with a break point in the DashboardApplication.HandleRequestMessage method you will see the bus has routed the request here. The method simply creates a basic response and publishes that response. Because the the DemoController is a subscriber to the ResponseMessage type it receives that message via its consume method, assigns it to a local variable and calls the request to be completed, which inturn calls the EndAsynch method.

the key points are the

Consumes.For

on the controller with its consume methods and the asynch calls to the bus. each framework will do this slightly differently

container.Resolve().Subscribe(HandleRequestMessage);

the subscribing to the request message

container.Resolve().Publish(response);

the publishing of the response message

If you want to see the inner working then the 3 projects under the mass transit folder contain all the juicy stuff. typically these would just be refence dll’s but the whole idea of sample is to see how the code works 🙂
Hopefully next up I may do a classic Asp.Net example to see if i actually get the concepts correctly (reading and writing are not the same things!) and can use the asynch methods from there.

————————————–
Setting up MSMQ

NB On XP You must have an edition that supports MSMQ (ie not home)

Go in to Control panel > add or remove programmes
Select the add/remove windows components
Select Message Queuing if it is not already selected and add it.

Now if you go to “Control Panel” > “Administrative Tools” > “Computer Management” under the “Services and Applications” branch, when expanded, you should see a “Message Queuing” branch.
If so you have MSMQ set up.

You now need to set up queues for an application to uses

From : http://infocenter.sybase.com/help/index.jsp?topic=/com.sybase.ebd.eai.help.src/setting_up_msmq.htm
Setting Up Microsoft Message Queuing (MSMQ)

To Set up MSMQ on your Server:

1. Go to Control Panel -> Add/Remove Programs -> Add/Remove Windows Components.

2. Select Message Queuing Services Component from the Windows Component Wizard.

3. Follow the directions provided by the Queuing Services Wizard.

4. After completing the Queuing Services Wizard, go to Control Panel -> Administrative Tools -> Computer Management -> Services and Applications -> Message Queuing.

To Create a Public Queue:

1. Right click the Public Queues Directory.

2. Select New.

3. Select Public Queue.

4. In the Queue Name Dialogue Box, enter the Queue Name, where the format is [machine_name]\[queue_name].

To Create a Private Queue:

1. Right click the Private Queues Directory.

2. Select New.

3. Select Private Queue.

4. In the Queue Name Dialogue Box, enter the Queue Name, where the format is [machine_name]\private$\[queue_name].

For Mass Transit you will need to create a private queue of the name “test_servicebus” and leave the default setting of NOT transactional.