Question

Information:

The incomming message is of type HL7. I'm using in the receive pipeline the "Flafile-Disassembler" and not the "BTAHL7 2.x Disassembler" pipeline component, because the HL7-Schema has is a bit modified and the BTAHl7 disassembler split the message (multipart messages) and we don't want; And we don't want to use orchestration.

Questions:

How can I create acknowledgements in a receive pipeline in BizTalk 2010, without using "BTAHL7 Disassembler" (without spliting --> multipart messages approach)?

Or, it's possible to prevent splitting the message in the BTAHL7 Disassembler pipeline component?

a positive ACK would be enough.

Thanks.

Was it helpful?

Solution

As @boatseller says, you cannot prevent the HL7 Disassembler from creating multi-part messages.

For your other question: you can create a custom pipeline component to send back the HL7 acknowledgement, and then just use your own flat file schema (with the out-of-the-box flat file disassembler pipeline component).

1. Use a two-way receive port.

This should work using a two-way port, even with the MLLP adapter, but you need to validate and test everything and understand that Microsoft may or may not support using the MLLP adapter without the HL7 2.X disassembler pipeline or using BizTalk in the manner suggested below.

2. Correlate the request and response.

You'll need a custom pipeline component in the receive location's pipeline to make BizTalk create a subscription for the response. Use the Pipeline Component Wizard to get a head start creating the component.

In the Execute method of your custom pipeline component class (which you get from implementing the IComponent interface), write something akin to the below code.

public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
{
    const string sysPropertyNamespace = "http://schemas.microsoft.com/BizTalk/2003/system-properties";
    var epmToken = inmsg.Context.Read("EpmRRCorrelationToken", sysPropertyNamespace);
    var correlationToken = epmToken != null
                                    ? (string) epmToken
                                    : Guid.NewGuid().ToString();
    inmsg.Context.Promote("EpmRRCorrelationToken", sysPropertyNamespace, correlationToken);
    inmsg.Context.Promote("RouteDirectToTP", sysPropertyNamespace, true);
    return inmsg;
}

The use or the EpmRRCorrelationToken and RouteDirectToTP properties for request-response message processing without an orchestration is documented in this MSDN blog post.

3. Create and Send the Acknowledgement

You can use another custom pipeline component inside your send pipeline to manually create the acknowledgement based upon the input message, perhaps with some additional pipeline component configuration that is read at runtime.

Like the first custom pipeline component, you can implement the IComponent interface's Execute method. Code like this should work:

public Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext pc, Microsoft.BizTalk.Message.Interop.IBaseMessage inmsg)
{
    string msgOut;
    var bodyPart = inmsg.BodyPart;
    if (bodyPart == null) 
        return inmsg; // Maybe throw an exception instead?
    var inboundStream = new ReadOnlySeekableStream(bodyPart.GetOriginalDataStream());
    inboundStream.Position = 0;

    using (var reader = new StreamReader(inboundStream))
    {
        var builder = new StringBuilder();
        // Read the input stream's first line - this should be the MSH segment:
        var firstLine = reader.ReadLine();
        // TODO: read search/replacement values from pipeline configuration
        // TODO: make a better ACK header than this
        builder.AppendLine(firstLine.Replace("ADT^A01", "ACK")); 
        // Construct your acknowledgement segment, preferably without hardcoding it here:
        builder.AppendLine("MSA|AA|ADT^A01");
        msgOut = builder.ToString();
    }

    // Write out the output
    var outputStream = new VirtualStream();
    var writer = new StreamWriter(outputStream, Encoding.Default);
    writer.Write(msgOut);
    writer.Flush();
    outputStream.Seek(0, SeekOrigin.Begin);

    inmsg.BodyPart.Data = outputStream;

    pc.ResourceTracker.AddResource(inboundStream);
    pc.ResourceTracker.AddResource(outputStream);

    return inmsg;
}

Other than handling the inline TODOs and adding in more null checking, that should be a fairly complete solution, though your mileage may vary, especially when it comes to returning a valid HL7 acknowledgement message.

Bonus. Why not use an orchestration?

This was asked in a comment to the question, and here are a few reasons for using custom pipeline components instead of an orchestration:

  1. Orchestrations are slow. Microsoft, in their own Optimizing Orchestration Performance article, says that you should avoid using orchestrations when possible. Orchestrations increase latency and response times because they require extra roundtrips to the BizTalk MessageBox database and additional processes and threads be spun up on the BizTalk server.
  2. Acknowledgments return faster. HL7 integrations typically use accept/receipt acknowledgements. Many systems will not send additional messages until the last-sent message is acknowledged. So if you have to wait for an orchestration to spin up, read the input, construct the ACK output, return the ACK to the port, and then send the ACK back, you will greatly slowdown processing. Yes, this is similar to #1, above, but it is important to understand.
  3. Orchestrations make your solution more failure-prone. An orchestration is another point of failure. If you have to take your ACK-producing orchestration or its associated host instance(s) offline, then you have lost your ability to receive messages. A great benefit to BizTalk is its ability to isolate the different parts of an integration solution, enabling high availability and increased reliability. When your decoupled receive port's pipeline components return the acknowledgement after simply publishing the inbound message to the BizTalk message box, your receipt of messages can continue, even when your internal systems/components are down.

OTHER TIPS

To answer you specific questions:

The HL7 ack is a specific function of the HL7 disassembler. You would have to create you own custom Disassembler component, running ffdasm internally, and generate your own ack to simulate the HL7 Disassembler's behavior.

No, I'm not aware of a way to prevent the HL7 Disassembler from creating Multi-Part Messages. You can easily recombine the segments in a Map executed in an Orchestration.

Couple of things here.

Number 1 - In my experience, orchestrations for HL7 should only be used in extreme cases. Our implementation only has a few where we need to spin out multiple messages from a single inbound message. Messaging only approach is best fit for HL7. They are costly and slow and to echo whats been said, add an extra point of failure.

Number 2 - Bits and pieces of what have been said are to be true, at least how i do it. You can bypass certain aspects of the DASM, and I do, because it is definitely not perfect. So i'd wrap it and include your custom functionality. The DASM returns a queue to the messaging engine that includes the disassembled message and an ack, you could dispose of the ACK and enqueue your own 'static' ack.

The DASM creates and queues the ACK in xml format so that the ASM on the send pipeline can assemble it back into raw HL7 format along with some other stuff. So you could either do the same in a custom pipeline component or find a way to call those private methods in the DASM that create the ACK and let it do it all for you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top