UCMA v2.0 includes a great abstraction layer, Communication Workflows, based on the Windows Workflow Foundation (WF).
These workflows are great for those needing to great simple yet powerful UC enabled applications. The workflow activities themselves are pretty self explanatory. I'll cover the activities themselves in another post.
The "difficult" portion of creating a UCMA workflow application isn't the actual workflow, but creating the host. Yes the default template wraps your WF application is nice little console application, but this is really only for debugging purposes. Are you really going to deploy your console application in production? Those familiar with Speech Server are probably scratching their heads, while Speech Server had a nice service and administrator console that allow you to easily point it to your Speech WF application, UCMA does not. You need to build it yourself and build it for every UC application you build, and to truly do that we need to know at least a little bit about the UCMA Core API. Joe Calev has a great blog which walks you through the Signaling portion of the Core API. For the WF API you really should have some understanding of the Collaboration portion of the Core API.
First you will need to make sure that you have a certificate on for your application and you will need to provision an application on the OCS Front End. You can do this by using the Application Provisioner and following these instructions: http://msdn.microsoft.com/en-us/library/dd253360(office.13).aspx
This is the key information that our application will need:
- Application Name
- Application Port
- Application SIP URI
- Application Server FQDN
- OCS Pool FQDN
- OCS Pool Port
- Certificate Information
Note: You should never call the asynchronous methods, synchronously. IE object.End(object.Begin). You'll see some of this in sample code and blog posts, do not use this is a production application!
Armed with the necessary information, we can start looking at some code:
First we need to use create an instance of the CollaborationPlatform, for this post the importance of this object is that it is used to describe our application. It has two constructors, one that takes a ClientPlatformSettings parameter and the other that takes a ServerPlatformSettings.
The different here is the ClientPlatformSettings will use an AD account, while a ServerPlatformSettings will use a Contact Object. We reference the Contact Object via the GRUU provided by the Application Provisioning tool. There are some features lost if you use the ClientPlatformSettings, such as Impersonation. I typically draw the line, if the application is going to consume the Audio or Instant Message call and perform some logic based on the input I use the ServerPlatformSettings. IE: Response Bots. If my application is just providing an abstraction method for a user that already has credentials to sign in and message users, then I would use the ClientPlatformSettings. IE: Build your own authenticated Web Messaging.
For this post, we will use the ServerPlatformSettings.
ServerPlatformSettings platformSettings = new ServerPlatformSettings(appName, appServerFqdn, applicationPort, gruu, cert);
CollaborationPlatform collabPlatform = new CollaborationPlatform(platformSettings);
Once the CollaborationPlatform object has completed starting up, we need to setup our EndPoint. There are two choices, ApplicationEndPoint and UserEndPoint, if you are using the ClientPlatformSettings then you need to use the UserEndPoint, since we are using the ServerPlatformSettings we need to use the ApplicationEndPoint.
ApplicationEndpointSettings settings = new ApplicationEndpointSettings(applicationUri, ocsFqdn, ocsTlsPort);
ApplicationEndpoint endpoint = new ApplicationEndpoint(collabPlatform, settings);
If our WF application is an Inbound application, we need to register for the type of calls the WF will handle, but remember that the WF can only accept AV and IM calls and can't accept conferencing calls. That’s not to say you couldn’t register to receive a conference invite, and handle the conferencing features using the Core API itself, but that is another post.
Once we have done that, we can establish our endpoint.
Next we need to start the Workflow Runtime and add the UCMA WF Services, this isn’t so much related to UCMA as it is to WF itself.
WorkflowRuntime workflowRuntime = new WorkflowRuntime();
Finally we need to route the call to our workflow, via the handler methods we registered for earlier.
When a call comes in, we need to pass the call to our workflow application and from there the Workflow handles the rest:
WorkflowInstance workflowInstance = workflowRuntime.CreateWorkflow(WorkflowType);
CommunicationsWorkflowRuntimeService communicationsWorkflowRuntimeService = (CommunicationsWorkflowRuntimeService)workflowRuntime.GetService(typeof(CommunicationsWorkflowRuntimeService));
communicationsWorkflowRuntimeService.EnqueueCall(workflowInstance.InstanceId, call); //Call object is passed by the receiving handler
communicationsWorkflowRuntimeService.SetEndpoint(workflowInstance.InstanceId, endpoint); //Endpoint object is a local variable
communicationsWorkflowRuntimeService.SetWorkflowCulture(workflowInstance.InstanceId, new CultureInfo("en-US"));
I was thinking about it and all of this is pretty repetitive code from one workflow to another workflow application, this all has to be done, everytime for every WF project. I’ve created a solution that I will release on CodePlex last this week. Basically the solution is a Windows Service that will take the parameters, GRUU, port, etc… log into OCS and route calls to the workflow you provide as a compiled assembly. Also part of this solution utilizes MSMQ, in much the same way Speech Server did. You can associate a MSMQ name to an application, if a message is in that queue if will fire off the workflow you specify or use the default built in WF application.
The Jist of it is, instead of worrying about writing all the code above, you can concentrate on just the workflow portion. Compile the WF as an Assembly instead of a Console application, add the application parameters to the App.Config of this UCMA Application Host service and you are done! A picture is worth a thousand words, so here is a high level picture of the solution.
I am also working on releasing the following solutions on CodePlex:
- Updated Web Chat sample. The current released Web Chat uses UC AJAX, this updated one will use UCMA 2.0, WCF & SilverLight.
- Client Framework. An abstraction layer to both UC Client and Communicator Automation.