Thursday, August 23, 2012

Microsoft XDS.b Solution Accelerator Patient Identity Feed woes


Recently in the lab we setup the XDS.b solution accelerator (http://ihe.codeplex.com). Overall the software works however we've identified some problems with the HL7v3 messaging that is returned from the Registry actor.

A little backstory first: I've been asked to teach the Mohawk course for electronic health records, and part of this teaching is a series of hands-on labs which students use tools to communicate with standards based health software packages. One of these labs is an IHE XDS.b lab. One of the servers uses OpenXDS, and the Microsoft XDS.b solution accelerator was used to illustrate different software using the same standard.

Anyways, we have a PIX Manager reference implementation in our lab and I wanted to setup the manager to act as an identity source to the XDS registry (via ITI-44 messaging rather than the ITI-46 notification system). I had this working however I noticed that when I sent messages after 12 minutes past the hour Everest's TS type would throw an FormatException, usually these read:
The date "20124002154000" is not a recognized date/time

Which looked a little suspicious, after some digging in the XDS.b solution accelerator's code I found this line in the PatientIdentityFeedLogic.cs:

public static readonly string PATIENT_ACK_DATETIME_FORMAT = "yyyymmddhhmm";

Which needs to be corrected to :

public static readonly string PATIENT_ACK_DATETIME_FORMAT = "yyyyMMddhhmm";

Not sure how this was missed at connectathon however it was causing issues with the PIX manager. After the change, the XDS Registry works!

Anyways, to anyone thinking of deploying the Microsoft XDS.b solution accelerator should change this line prior to deployment. Additionally, use the instructions in the latest Sync package as these are correct.

Tuesday, August 21, 2012

Custom SOAP Headers


Wow, it has been awhile since I've been able to post any new content on this blog. It has been a very busy summer and I have to say that there are a few great projects that I've been working on and hope to release to the wild in a few weeks/months time.

In the meantime, I thought I'd post some code samples illustrating some of the new features of the WCF connector in the upcoming Everest 1.0.2 release (a minor update and bug-fix release). If you've ever had to use the WcfClientConnector or WcfServerConnector, you'll know that dealing with SOAP headers was … well… cumbersome. It required setting some odd properties and wasn't really thread safe. This has been addressed in the 1.0.1 release.

For this example, I'll show you how to read/write the WS-Addressing headers in a received message from the WCF connectors. First, to access the SOAP headers from a message received from a WcfServerConnector, you can simply access the Headers property on the WcfReceiveResult. The following code is written in the MessageAvailable event handler for a WcfServerConnector:

static void conn_MessageAvailable(object sender, MARC.Everest.Connectors.UnsolicitedDataEventArgs e)
{
     // Get the sending connector that raised the event
     var connector = sender as  WcfServerConnector;
     if (connector == null)
          throw new ArgumentException("Must be called from a WcfServerConnector", "sender");
     // Receive the message
     var receiveResult = connector.Receive() as WcfReceiveResult;

Pretty standard Everest stuff, next we'll emit the value of the WS-Addressing headers:

if (receiveResult.Headers != null){

     Console.WriteLine(receiveResult.Headers.To);

     Console.WriteLine(receiveResult.Headers.Action);

}

We can access the Headers array just like any other WCF Header, this applies to constructing the response as well. To construct the response, populate the ResponseHeaders on the receiveResult prior to call "Send()" on the server connector.

receiveResult.ResponseHeaders = new System.ServiceModel.Channels.MessageHeaders
(receiveResult.Headers.MessageVersion);
receiveResult.ResponseHeaders.Add(MessageHeader.CreateHeader("myHeader", "urn:my-ns:com", "Value"));
connector.Send(new MCCI_IN000002CA(), receiveResult);

This code will return the following soap header:

<tns:myHeader xmlns:tns="urn:my-ns:com">Value</tns:myHeader>

More complex headers can be added the same way you would add standard System.ServiceModel.Channel.MessageHeader objects. It is also possible to send message headers using the overridden Send() method on the WcfClientConnector:

var conn = new WcfClientConnector();
// trimmed
MessageHeaders messageHeaders = new System.ServiceModel.Channels.MessageHeaders(MessageVersion.Soap12);messageHeaders.Add(MessageHeader.CreateHeader("myHeader", "urn:my-ns:com", "Value"));
conn.Send(instance, messageHeaders);

As I said, this enhancement will be available in the 1.0.2 release of Everest, or is available in the 1.0 branch of the Everest SVN server (or the trunk if you're feeling adventurous and want to try Everest 1.2 features out as well).