A fellow BizTalk developer asked me today how we go about implementing send port retires when using ESBT. ESBT itineraries deliver dynamic routing via dynamic send ports. i.e. the configuration of the endpoint is stored within a store such as UDDI, BRE, SQL and resolved at runtime using endpoint resolvers, the endpoint config is then applied to the dynamic send port via the appropriate adapter provider. Think of it as JIT send port configuration. Note there is a way to trick the itinerary and use static send ports if the scenario requires, see here for more details on this technique.
With a traditional BizTalk solution we may choose to create a pipeline component that works with the BTS.RetryCount, and BTS.RetryInterval properties from the BTS namespace. Basically we need a component that will run under the context of the send port. With ESBT we have another option, ESBT itineraries allow us to develop custom itinerary services then within the itinerary define where those services will execute. e.g. execute under the context of a receive handler or send handler of a receive or send port. This is the approach we are going to demonstrate here.
First step is to create an itinerary. Keep it simple. Receive a message, and send a message. To do that we need an On Ramp which is bound to a receive location, an itinerary service that implements the Off-Ramp extender, and an Off Ramp which is bound to a dynamic send port. The Off ramp extender implements a static resolver in this case to define the endpoint details that will ultimately be used by the dynamic send to route the message.
Deploy and test the above and make sure your itinerary is functioning. A good option would be to configure the static resolver to write to C:\SomeFolder. Create SomeFolder on the C:\. Check you can route messages. Then rename SomeFolder and test your message suspends or is routed to the ESBExceptionDb if you have failed message routing and the ESBT Exception management framework configured.
Next step is to create a custom itinerary service that is going to run under the context of our send port and implement the retry. Follow the steps here to implement a basic messaging itinerary service. You should end up with something that looks like the below.
Now add your new itinerary service to your itinerary. Note I added a “Dummy” static resolver to my itinerary service and then set the Container property of my itinerary service to be the send handler of the Off Ramp. This means the itinerary service will execute under the context of the dynamic send port when attempting to send the message, much as a send pipeline. Your itinerary should end up looking something like below.
Give the above a test and ensure you are hitting the itinerary service. You can add a break point in your itinerary service and attach Visual Studio to the host instance running your dynamic send handler for your dynamic send port. On an environment running multiple in-process BizTalk hosts use the tip here to help identify the appropriate process to attach to.
Now you’ve tested your new itinerary service lets add the retry logic. From your itinerary service project add a reference to Microsoft.BizTalk.GlobalPropertySchemas.dll then plug in the code. Your code should end up looking something like below. Basically we are using the BTS helpers from the GlobalPropertySchemas assembly to interact with the message context to get the information we need about how BizTalk is processing the message. First up we get the actual number of transmission attempts the send handler of the dynamic send port has attempted. i.e. if we have 5 reties and BizTalk has tried to send a message but failed 3 times then this setting will be 3. Next we calculate what we should set the RetryCount context property too. I’ve just hardcoded the retryCount and retryInternal for the sake of this demo. By calculating the retry count using the actualRetryCount and then setting the retryCount context property we are effectively decrementing the retry count each time the itinerary service executes.
Give it a test. Rename your C:\SomeFolder as defined in your static endpoint resolver to something invalid so the send handler fails. Attach Visual Studio to the itinerary service and watch the retry count decrement. Before the retry count is exhausted rename the C:\SomeFolder send location to be valid again and watch the send port retry and successfully send the message to the endpoint.
That’s it! Too easy!