Tuesday, 14 February 2023

HL7 Soup XML attributes

HL7 Soup supports attributes in the expressions, however, the binding tree doesn’t show them as bindable entities.  This means you have to manually type in the path that includes the attribute address.  You can do that with an @ followed by the attribute name.

For example:

<Patient>
    <ID ext=”test”>1000</ID>

 

The path for the extension attribute would be

Patient/ID/@ext

 

Note you still need to have a binding and not just text.  So the easiest way is to bind to the field, then manually edit the path. You can do this in the transformers.


Wednesday, 16 November 2022

Loop over HL7 OBX fields and add the results to a database

I needed to loop over OBX segments in an HL7 message, then extract the values and write them to a database.

There are several ways of doing this, such as calling a sub-workflow, but I wanted a single-step process, so instead I just created the c# code in a Code Activity.  It's pretty straightforward.  HL7 Soup has a great API for working with HL7, and I use both Looping over segments as well as the simple to use GetValueAtPath.  API details can be found here.

Note that you can also turn this into a reusable activity following these steps.

//Bring in the assemblies that we need that are not included by default.
#r "C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.1\System.Data.dll"

string connectionString = @"Server=xps17\sqlexpress;Database=HL7 Soup;User Id=HL7 Soup;Password=xxx;";
//Get the message template
IHL7Message message = (IHL7Message)activityInstance.Message; //Use IHL7Message for HL7 Messages and IMessage for other message types

using (System.Data.SqlClient.SqlConnection connection = new System.Data.SqlClient.SqlConnection(connectionString))
{
    //get other values not in the loop
    string patientName = message.GetValueAtPath("PID-5.2");
    
    connection.Open();
    
    //Get all OBX segments and loop over them
    IHL7Segments allSegments = message.GetSegments("OBX");
    foreach (IHL7Segment segment in allSegments)
    {
        //update your database
        using (System.Data.SqlClient.SqlCommand command = connection.CreateCommand())
        {
            string obxvalue2 = segment.GetField(2).Text; 
            string obxvalue5 = segment.GetField(5).GetComponent(1).Text;
            
            command.CommandText =$"Insert into MyTable (fieldname, fieldname2,fieldname3) values ('{patientName}','{obxvalue2}','{obxvalue5}')";
            command.ExecuteNonQuery();
       
        }
    }
    connection.Close();
}

Wednesday, 21 September 2022

HL7 Soup Licensing Proxy error

I was attempting to license HL7 Soup and Integration Host on a hospital network, but I was getting an error preventing the license number from activating.

The problem was that the calls went through a proxy server.

The solution was to open the .config file for each app and uncomment the section that tells the proxy server to use the default credentials.

 <system.net>

    <defaultProxy useDefaultCredentials="true">

    </defaultProxy>

  </system.net>


This isn't credentials for calling the server, just the proxy server.



Monday, 22 August 2022

Integration Host HTTP sender as code

 The HTTP Sender in HL7 Soup's Integration Host is simple to use, but doesn't expose every possible feature of HTTP messaging.  I had to retrieve response headers, and these are not provided back in the UI.

Fortunately it uses c# in the code activity, so I was able to add the following code to save the day.


 //The following code is just a indication for getting started for an Activity. Edit or delete as you wish. Use the variable workflowInstance and activityInstance to access the running states of the workflow.

using System.Net;
using System.IO;

Encoding encoding = Encoding.UTF8;
               
using (WebClient client = new WebClient())
{
    client.UseDefaultCredentials = true;
    
    client.Headers.Add("Content-Type","text/plain"); 
    
    //Add all the headers that you want.
    // client.Headers.Add("yourHeaderName", workflowInstance.GetVariable("yourVariableName"));
    
    
    byte[] data = null;
       
    //Payload for posts if you need it.
    //var payload = "";
    //if (posting the message)
    //{
    //   payload =activityInstance.Message.Text;
    //    if (payload != null)
    //     {
    //        data = encoding.GetBytes(payload);
    //    }
    //     else
    //     {
    //         data = new byte[] { };
    //     }
    // }
    
    //credentials
    client.Credentials = new NetworkCredential("","");
    
    
    
    //Get the method as a string.
    string method = "GET";
    
    string url = HTTP://url.com";
    
    //Call HTTP Service
    string result = "";
    if (method == "GET")
    {
        //Get cannot pass a payload
        using (Stream stream = client.OpenRead(url))
        {
                 using (var streamReader = new StreamReader(stream))
                {
                    result = streamReader.ReadToEnd();
                }
         }
    }
    else
    {
        //Post, Put and Delete pass a payload.
        var bytes = client.UploadData(url, method, data);
        result = encoding.GetString(bytes);
    }
    
    if ( client.ResponseHeaders!=null)
    {
        foreach (var responseHeader in client.ResponseHeaders)
        {
            //process your response headers
            //e.g.
            workflowInstance.SetVariable("MyVariable", responseHeader.ToString());
        }
    }
    
}

Sunday, 8 May 2022

Processing HL7 in the Cloud

While Integration Host has long been my preferred program for processing HL7 messages I've only really used it in local settings. Being able to handle workflows in the cloud was something I've wanted to do for a while now so you can imagine my delight when I saw the announcement on their website that their program was now available as a Docker container and that they'd already published a tutorial on getting it up and running on Azure as a container instance. 

 It's stupidly easy to get going and the Azure container instance pulls directly from their Dockerhub repo so there's no mucking around with downloading and uploading files. All in all, I can see this being a popular way to use Integration Host going forward.

Tuesday, 22 February 2022

Change HL7 Soup Senders or Receivers to a text Encoding that is not listed

 Not all text Encodings are listed in the HL7 Soup UI.  It makes it too noisy for most users, so only the common ones are there. However, you can change it to any installed encoding via the following steps.

  1. Create your sender. Set the Encoding to 8859-1 and save it.
  2. Close HL7 Soup
  3. Load the file in notepad C:\ProgramData\Popokey\HL7Soup\Settings\1\FunctionSettings.json
  4. Search in the file for the name of your sender.
  5. Change the Encoding property to your Encoding. Google "C# encodings" if you want to find the official encoding name.
  6. Save the file
  7. Reopen HL7 Soup.

Now, if you send with that sender, it will use your Encoding.

Monday, 13 December 2021

Sending Client Certificates with an HTTP Sender in Azure

If you are running inside an Azure App Service and you need to send a client certificate with you message, you'll need to follow these steps. 

             1. To configure the location on the key vault in the config "KeyVault:VaultUri".  Set it with the URL of your Azure Vault

             2. Another app setting, set "WEBSITE_LOAD_USER_PROFILE" with the value of "1".  Without this you will get the error "The system cannot find the file specified"

             3. Add a certificate with a private key in the Azure vault.  You can generate one in the azure vault.

             4. Under the App Service settings/Identity/System Assigned, turn status to ON.  Copy Object ID

             5. In the Vault / Access Policies, Add Access Policy.  

             6. Add Secret Permissions (Get)

             7. Add Certificate Permissions (Get, List)

             8. Set the Principle to the App Service using the object ID you got at step 4.

             8.1 Click "Add", and then also click "Save".  "Add" doesn't save even though the window closes, and this caused me much frustration.

             9. In the workflow, configure the http sender to use the vaults name of the certificate as the thumbprint.

             10. This was a very helpfull page that enabled me to work all this out

 

Note:  Integration Host stores the certificates once they have been acquired in memory.  It costs money and performance to keep pulling the certificate from the vault.  If you update the certificate, don't forget to restart the app.