Lately some colleagues and I noticed that some services were not started automatically when the system was booted (Windows 2008 + BizTalk Server 2009). We didn’t took the time to dive into this, but Thiago Almeida did; see his blog why this is happening and how to solve this. You can also check the Microsoft site.
Monthly Archives: September 2009
Can the Healthcare take benefits of an ESB?
In an Enterprise Service Bus you have several services which are loosely connected via several transport mechanisms. The Healthcare uses the standard HL7 for communication between systems, hardware and software. Most of the time MLLP (Minimal Lower Layer Protocol) is used for transport. Because in an ESB architecture systems are loosely coupled, some challenges can arise when messages must be processed sequentially.
For example: consider the next 3 ADT messages: with A01 (patient admit), A02 (patient transfer) and A03 (patient discharge). This is also the sequence/order the messages must be delivered to other systems. You can’t discharge (A03) a patient if the patient is not admitted (A01).
In an Spoke and Hub or Enterprise Application Integration architecture you can connect the systems with each other and make the process sequential. BizTalk Server works asynchronous, so messages are dropped in the MessageBox and processed by a subscriber, which can be an Orchestration or Send port. Example: if the Send port process the second message (A03) faster as the first message (A01) which is used in an Orchestration, then the backend system will return an error (BizTalk processing is also known as: first-in, fastest out). To make this process synchronously BizTalk Server and the MLLP adapter offers some techniques which can be used:
- Ordered Delivery on the receive port.
- Listen-shape in an Orchestration together with a correlation set based on the Patient ID.
- Make use of guaranteed delivery.
- Wait for ACK/NACK response from the backend, before continuing to the next message.
But how to solve this in an ESB architecture? How to solve this with BizTalk Server ESB Toolkit 2.0?
My answer to this question in the title is: yes it can. How? The ESB Toolkit makes use of BizTalk Server, and is therefore based on rules prescribed by BizTalk. The Itinerary will become just a context property on a message for routing thru the BizTalk system. So you can still make the process synchronously. The Orchestration must use a “request” / “response” mechanism to send the message to the backend system, and wait for an ACK before processing the next message. Some blogs from my this month can help to make this happen, also for a generic solution.
Let me know how you think about this or if you have already experience with HL7, MLLP and the ESB Toolkit.
How to dynamically route a message in the ESB to a static port
What is the problem? Consider the next Itinerary:
A message is received on the on-ramp, it is transformed to our HL7 message and after that send to an Orchestration. In the Orchestration the message parts MSHSegment (Header information) and ZSegments are added as part in a multipart message. This Orchestration is a generic process (service as you wish) for extending HL7 messages. After that the multipart messages must be routed to the off-ramp, which must be connected to the MLLP Adapter (from the Microsoft BizTalk Server HL7 Accelerator).
But, the MLLP Adapter is a static adapter and not dynamic. This means that no property schema is available for the MLLP transport settings (and if it was, the MLLP send adapter is not programmed that way). This means that no custom ESB adapter provider can be created and this means that you can’t use the MLLP Adapter in an ESB solution. You can’t use the MLLP Adapter in the Itinerary, because you can only use dynamic ports, and the MLLP Adapter has no possibilities to configure it dynamically (setting context properties for the transport).
I would like to see that Microsoft add some new features to the HL7 Accelerator: use it in a dynamic solution. But till that time, I’ve to use another way to get the benefits of the ESB Toolkit and thus my Itinerary (which can be successfully validated). Below I will describe my solution.
Because the MLLP Adapter can only be used in a static scenario, I created a static send port. For this solution I used an one-way port, and I don’t care for the ACK and NACK right now (will be a next blog). Because I want to use the power of the ESB Toolkit, I added a filter to my port:
I’m using my custom send pipeline with the ESB Dispatcher component, HTAHL7 2.x Assembler component (TrailingDelimiterAllowed on True!) and the ESB Itinerary Cache component:
As I mentioned above, you can only use dynamic ports in the off-ramp. So I created a dummy send port (or use an existing one). This dummy port I’m using in my itinerary:
Because my off-ramp has now the wrong values for Service Name, Service State and Service Type, I’ve to overwrite them so the filter is working correctly. Because I want to change my routing easily I define those settings in UDDI. I created a service ‘sendfilterformedicalsystemx’ and a binding ‘MyMLLPBackendSystem’:
Notice that I only added one instance info. I gave the binding a meaningful name so I can use it in the Itinerary:
Don’t forget to add a Category to this binding, else you will receive an exception during testing (see a blog from my earlier this month). It really doesn’t matter now what is in here so I added the transporttype:
And as latest in UDDI I add only one Instance Info: microsoft-com:esb:runtimeresolution:endpointconfig . This property has the next values:
As you can see, this property contains my filter keys and values for my send port. Now my UDDI service is registered (only for filter properties) I can finish my Itinerary. I can fill in the binding key in my UDDIResolver: uddi:esb:systemx
To continue the Itinerary in the ESB the right properties must be set in the Orchestration (note: Itinerary processing takes plance in receive- and send pipelines and Orchestrations). Some are basic and described on the site of Microsoft.
First I execute the next statements to retrieve the Itinerary and the current step:
itinerary = new Microsoft.Practices.ESB.Itinerary.SerializableItineraryWrapper();
itineraryStep = new Microsoft.Practices.ESB.Itinerary.SerializableItineraryStepWrapper();itinerary.Itinerary = Microsoft.Practices.ESB.Itinerary.ItineraryOMFactory.Create(InboundMsg);
itineraryStep.ItineraryStep = itinerary.Itinerary.GetItineraryStep(InboundMsg);
Because the next service in the Itinerary can be used, the next step must be retrieved:
itinerary.Itinerary.Advance(msgPharma, itineraryStep.ItineraryStep);
//itinerary.Itinerary.Write(msgPharma);
For my scenario the Write is not necessary. From the current service (my UDDI Resolver) I can retrieve my endpoint settings from UDDI and put them on the context of my message, so it will be published to my static send MLLP send port:
resolverDict = Microsoft.Practices.ESB.Resolver.ResolverMgr.Resolve(InboundMsg, itineraryStep.ItineraryStep.ResolverCollection[0]);
filterKeys = resolverDict.Item("Resolver.EndpointConfig");ServiceName = OrchestrationHelper.GetConfigItem(filterKeys, "ServiceName");
ServiceState = OrchestrationHelper.GetConfigItem(filterKeys, "ServiceState");
ServiceType = OrchestrationHelper.GetConfigItem(filterKeys, "ServiceType");msgPharma(Microsoft.Practices.ESB.Itinerary.Schemas.ServiceName) = ServiceName;
msgPharma(Microsoft.Practices.ESB.Itinerary.Schemas.ServiceState) = ServiceState;
msgPharma(Microsoft.Practices.ESB.Itinerary.Schemas.ServiceType) = ServiceType;
ResolverMgr.Resolve will resolve my UDDI Service and retrieve all the information I defined. The resolver dictionary will contain my EndPointConfig. Now it is just a matter of getting the right values (split a string) and place them on the context.
As you can see it isn’t that difficult, but I’m still not quiet happy with this solution (dynamic MLLP Adapter is preferable). I hope it gave you an idea how to use UDDI, Itineraries and Static Ports. The next challenge will be to send a message to a MLLP system, receive an ACK/NACK (or nothing), and return this information to the calling system: all of course defined in an Itinerary. I hope to blog about this very soon.
If you have questions, remarks or other ideas please contact me. Thanks for reading.
New release BizTalk Software Factory
Jean Paul Smit has released a new version of the BizTalk Software Factory. This version has been updated to Visual Studio 2008 and BizTalk Server 2009. A nice new feature since this year is the integration of the BizTalk Deployment Framework (5.0 beta). Also Unit Testing with schemas and mappings are included.
Check it out on: http://bsf.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=32987
UDDI ArgumentNullException: Value cannot be null
I received the message in the EventLog: Value cannot be null. Parameter name: binding
xlang/s engine event log entry: Uncaught exception (see the ‘inner exception’ below) has suspended an instance of service ‘project.orchestration(782dca1d-7bf7-acae-1545-cb3861ca1a3b)’.
The service instance will remain suspended until administratively resumed or terminated.
If resumed the instance will continue from its last persisted state and may re-throw the same unexpected exception.
InstanceId: 3404f012-f181-4e83-8d45-d9537f40a712
Shape name: ConstructMessage_1
ShapeId: 52a16d91-9de3-494b-8f43-a9a8f0459371
Exception thrown from: segment 1, progress 25
Inner exception: Value cannot be null.
Parameter name: binding
Exception type: ArgumentNullException
Source: Microsoft.Practices.ESB.Resolver.UDDI3
Target Site: Void ExtractBindingCategoryInfo(Microsoft.Practices.ESB.UDDI3.categoryBag, System.String, System.Collections.Generic.Dictionary`2[System.String,System.String])
The following is a stack trace that identifies the location where the exception occuredat Microsoft.Practices.ESB.Resolver.UDDI3.ResolveProvider.ExtractBindingCategoryInfo(categoryBag categoryBag, String keyPrefix, Dictionary`2 uddiValues)
at Microsoft.Practices.ESB.Resolver.UDDI3.ResolveProvider.ResolveUddi(String config, String resolver, String keyPrefix, Dictionary`2 resolutionOrig)
at Microsoft.Practices.ESB.Resolver.UDDI3.ResolveProvider.Resolve(ResolverInfo resolverInfo, XLANGMessage message)
at Microsoft.Practices.ESB.Resolver.ResolverMgr.Resolve(ResolverInfo info, XLANGMessage message)
at Microsoft.Practices.ESB.Resolver.ResolverMgr.Resolve(XLANGMessage message, String config)
at Microsoft.Practices.ESB.Itinerary.OM.V1.ItineraryV1.Advance(XLANGMessage message, IItineraryStep step)
at BTAHL7Schemas.ChangeHL7.segment1(StopConditions stopOn)
at Microsoft.XLANGs.Core.SegmentScheduler.RunASegment(Segment s, StopConditions stopCond, Exception& exp)For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
I ran into this problem earlier, see one of my old posts about manually configuring UDDI. In my case I forgot to enter the Category information for the UDDI service in the tab Categories:
How to debug an Orchestration in BizTalk Server 2009
There are two ways to debug an Orchestration (or three if you use Diagnostics.Debug or other methods):
* Standard way via BizTalk Management Console (not described here), easy in use and gives a lot of information on the flow of your Orchestration and values of your messages and variables.
* But sometime you want more information on components/objects and then it is easier to use normal Visual Studio debugging.
When compiling a BizTalk Server 2009 project in Visual Studio classes (.cs) files are generated for the BizTalk artifcats. Those files are not part of the project and have the extension ‘.cs’, e.g.: .btp.cs, .xsd.cs, .btm.cs
I was expecting also a .odx.cs file, but that is not the case. The cs file for the Orchestration is placed in “obj\Debug\BizTalk\XLang” and is called File0.cs. If you open this file you can attach this file to your BizTalk process (where the Orchestration is hosted in) and of course place a breakpoint.
Thanks to Thiago Almeida who pointed me on this via Twitter.
BizTalk RFID Mobile presentation
A nice presentation has been given on the TechEd in Australia. On this site you can find the presentation and the demo code.
Cannot create a custom ESB Adapter for MLLP
As you have noticed I’m working on HL7 and the ESB Toolkit. It is possible to extend the ESB Adapters with your own adapters by using the BaseAdapterProvider in Microsoft.Practices.ESB.Adapter. To use this it must be possible to dynamically configure your ‘normal’ BizTalk adapter (e.g.: by editing the properties in the propertyschema in an orchestration). The MLLP Adapter for HL7 messaging doesn’t support dynamically configuring from the send port. This is a real pity, because now I’ve to use the MLLP Adapter in a static way. (note: there is no property schema for MLLP on the system, and it is mentioned once on this site).
It would be nice if this will be a feature in the next release (or update) from the HL7 Accelerator.
HL7 Serialization error: Trailing delimiter found
I received the next error in the EventLog:
Error # 1
Segment Id: EVN_EventType
Sequence Number: 1
Field Number: 2
Error Number: 207
Error Description: Application internal error
Encoding System: HL7nnnn
Alternate Error Number: Z100
Alternate Error Description: Trailing delimiter found
Alternate Encoding System: HL7-BTAError # 2
Segment Id: EVN_EventType
Sequence Number: 1
Field Number: 4
Error Number: 207
Error Description: Application internal error
Encoding System: HL7nnnn
Alternate Error Number: Z100
Alternate Error Description: Trailing delimiter found
Alternate Encoding System: HL7-BTAetc
This can be easily solved by turning the property TrailingDelimiterAllowed to True (in the send pipeline component BTAHL7 2.X Assembler):
Note: if you have defined a party, then you can also configure this in the BTAHL7 Configuration Explorer:
BTAHL7 2.X Assembler error
I created a send pipeline with the HL7 Accelerator pipeline component for assembling the Xml to flatfile (ignore my naming convention
:
A message sent to adapter "FILE" on send port "SendPort2" with URI "C:\temp\BizTalk\Demo (HL7)\_out\%MessageID%.txt" is suspended.
Error details: There was a failure executing the send pipeline: "BTAHL7Schemas.SendPipeline1, BTAHL7 Project1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9460acab21d7a82a" Source: "BTAHL7 2.X Assembler" Send Port: "SendPort2" URI: "C:\temp\BizTalk\Demo (HL7)\_out\%MessageID%.txt" Reason: Object reference not set to an instance of an object.
MessageId: {F75F302D-B8F0-411B-B99D-7FB31DBC6AFD}
InstanceID: {65E819F3-CE2E-4F5A-A4D2-AF16BDB72DF8}
After some searching I find that I was forgotten to set some context properties:
msgOutgoing(BTAHL7Schemas.MSH1) = 124;
msgOutgoing(BTAHL7Schemas.MSH2) = "^~\\&";
msgOutgoing(BTAHL7Schemas.ParseError) = false;
msgOutgoing(BTAHL7Schemas.SegmentDelimiter2Char) = true;
msgOutgoing(BTAHL7Schemas.ZPartPresent) = false;
msgOutgoing(BTAHL7Schemas.MessageEncoding) = 65001;




