CruiseControl.NET – vNext – Trialling the New Communications Infrastructure
Work on vNext has unfortunately slowed right down at the moment (mainly due to university having started again) but I have managed to spend a little bit of time playing around with the communications side. In the current versions of CruiseControl.NET it is a pain to add a new method to the client API – there is around half a dozen classes that need to be modified just to modify the API plus the actual implementation details (and getting to the implementation.)
In vNext I want to make adding a new method as simple as setting an attribute on a method
I’ve already talked a bit about the design in my posts on Universal Naming, Three External Methods and Invokable Methods, with this in place I was ready to test whether it would work or not.
To do this I put together a simple command-line application to work as an interactive “console”. This has a few simple commands that the user selects for performing the various operations. It’s not much to look at but it does allow some simple testing:
The main commands are:
- query (? for short): this lists the available commands for the current URN
- invoke command (.command for short): invokes the command on the remote server
- up name (+name for short): adds the name to the current URN
- down (- for short): removes the last part of the current URN
- quit: exits the console
This provides the basics for querying, invoking and navigating the remote server. In the above screenshot I’ve shown an example of how this works.
Note: this console has a large number of limitations at the moment – it is only a proof of concept for testing!!
In the above screenshot there are only two commands available on a project – Start() and Stop() – not enough to do much with a project. It would be nice to add a command to retrieve the current status. So I opened the code for Project and added the following method:
public virtual Messages.SingleValue GetStatus(Messages.Blank request)
{
var response = new Messages.SingleValue(this.State.ToString());
return response;
}
The method is very simple – all it does is return the current state as a string. In order to expose a method in the API a method needs to have a single input argument and a return value. In the Common library I’ve added some basic messages in the Messages namespace to simplify this process.
Note: at the moment the console only handles messages that take in a blank message – I did warn you there are severe limitations ![]()
The next step is to expose this as an action in the API. This is as simple as adding a RemoteAction attribute:
[RemoteAction]
[Description("Retrieves the current status of the project.")]
public virtual Messages.SingleValue GetStatus(Messages.Blank request)
{
var response = new Messages.SingleValue(this.State.ToString());
return response;
}
I also added a description attribute to provide some help on action.
Note: yet another limitation in the console – no way to see this help yet – the server is actually returning the information
Now I can query the server and see the new method. When I call the method it will return the current state:
Nice and simple to add a new command to the API
Of course, there is a lot more work to do on the client side but at least the workload has been reduced on the server development!
Now, the next question is what if we want a different result set than one of the standard messages? Again this is easy enough to implement. First add a new class for the return response:
public class ProjectStatus
{
public string Status { get; set; }
public DateTime LastBuildDate { get; set; }
}
And then use the class in the method:
[RemoteAction]
[Description("Retrieves the current status of the project.")]
public virtual Messages.ProjectStatus GetStatus(Messages.Blank request)
{
var response = new Messages.ProjectStatus
{
Status = this.State.ToString(),
LastBuildDate = this.PersistedState.LastIntegration.FinishTime
};
return response;
}
Now when we call the command we get the custom message returned instead:
So still nice and easy ![]()
For those who want to know the technical details:
- The messages are encoded as XAML, hence why the cyan text in the screen shots is XML. XAML handles the serialisation and deserialisation nicely without any extra work on our part.
- The querying and invoking is done via reflection. The ActionInvoker class in the code is responsible for this.
- The communication is all via WCF at the moment – and there are two possible channels (HTTP basic and NET.TCP). However both are extendable and over time these will be expanded.
- There is a simple class in the Common library called ServerConnection which implements the low-level client functionality. In time I hope to build some higher level APIs to make it really easy to use.