Distributing an Axum Application

Note: a variant of this text also appears in the Axum Programmer’s Guide, which will be distributed with the upcoming CTP.

Axum has great support for writing distributed applications. In fact, one of the reasons for taking such a hard line on isolation is so that domains can interact locally or remotely with no change in the model. By borrowing a page from how the Web is programmed and making it scale to the small, we can easily go back to its roots and interact across networks.

With domains being services of a SOA application,  agents the protocol handlers, and schema the payload definitions (btw, schema are XML-schema compliant), we have an easy time mapping Axum to web services.

In the runtime that will be in the CTP, we have support for local, in-process channels as well as WCF-based channels.

To reach an agent within a domain, you have to give it an address; this is true in local and remote scenarios alike. Within a process, it’s a bit easier, because the agent type name itself acts as a “default” address if nothing else, but in the distributed scenario, we have to do a bit more. But it’s just a little bit.

The Axum runtime does this through an interface called IHost, which allows you to give the agent an address within a domain. To be precise, what we associate with an address is a factory for agents of the hosted type, which is used to create agent instances when someone creates a new connection. Each underlying communication / service hosting framework has to have its own implementation of IHost; Axum comes with one for WCF and one for in-process communication.

The address may be associated with an existing domain instance, in which case created agent instances are associated with that domain, or it may be associated with no domain instance, in which case created agent instances are associated with a new domain instance, one for each new connection.

For example, if you are building an Axum-based server, you can host domains as services with the following code:

channel Simple
{
input string Msg1;
output string Msg2;
}

domain ServiceDomain
{
agent ServiceAgent : channel Simple
{
public ServiceAgent ()
{
// Do something useful.
}
}
}

agent Server : channel Microsoft.Axum.Application
{
public Server ()
{
var hst = new WcfServiceHost(
                      new NetTcpBinding(
SecurityMode.None, false));

hst.Host<ServiceDomain.ServiceAgent>(
"net.tcp://localhost/Service1");
}
}

Each time some client connects to the address "net.tcp://localhost/Service1,” a new instance of ‘ServiceAgent’ will be created, associated with a brand new ServiceDomain instance. If instead, we wanted created agents to be associated with a single domain instance, we have to pass one in to ‘Host’:

hst.Host<ServiceDomain.ServiceAgent>(
     "net.tcp:...",
new ServiceDomain());

There is a corresponding interface for the client side, called ICommunicationProvider. This is used to create a new connection to an Axum service (or any service, for that matter, we have no knowledge that it’s written in Axum, a consequence of loose coupling). It, too, must have a version for each underlying communication framework and the Axum runtime comes with one for WCF and one for in-process communication.

Connecting to the service above would look like this:

var prov = new WcfCommunicationProvider(
new NetTcpBinding(SecurityMode.None, false));

var chan = prov.Connect<Simple>("net.tcp://localhost/Service1");

Of course, you don’t have to create a new communication provider for each connection, or a new host for each Host call.

That’s pretty much it – you just make sure that you choose the right WCF binding, and it’s off to the races with WCF doing all the hard work for us. If you are using schema types to define your channel payloads, they are already DataContract-compliant and safe to use for both inter- and intra-process communication.

As it turns out, this is no different from how you program Axum within a process boundary: the only different is what concrete IHost/ICommunicationProvider implementations you use, and what the addresses you create for your agents look like. In other words, the programming model for distributed and local concurrency in Axum applications is identical.

Anyway, that’s the short intro, but there’s not much else to it. The CTP won’t have any non-programmatic means of defining bindings, creating connections, or hosting services, but we would love to hear of your experiments with such things. Axum is a language, so we’re not really trying to solve things like that.

Niklas Gustafsson
Axumite