Creating a Custom Itinerary Messaging Service
The itinerary framework that is part of the Microsoft BizTalk ESB Toolkit supports execution of itinerary steps using classes implementing the IMessagingService interface that execute itinerary messaging services. You can implement a custom messaging service when you want the service to be responsible for the following:
Custom message validation configured in the itinerary
Custom message transformation configured in the itinerary
Custom processing of the message
In all these cases, a custom itinerary service that you implement acts as an interceptor and is called by the Dispatcher pipeline component.
Custom messaging-based itinerary services, or messaging services, all implement the IMessagingService interface. This interface exposes the Name and SupportsDisassemble properties and the Execute and ShouldAdvanceStep methods.
The Name property is the name of the service as it will appear in an itinerary. It must match the configured name in the itinerary services configuration in the Esb.config file.
The SupportsDisassemble property indicates whether the custom messaging service you are creating supports disassemble and the execution of multiple resolvers.
The ShouldAdvanceStep method takes in the current itinerary step, and the current message, and returns a Boolean value that indicates whether the dispatcher should advance the itinerary after the service executes. In almost all cases, this method should return true.
The Execute method is of greatest importance for a messaging service and contains the logic that will be executed at run time. It takes in the pipeline context, the message, the resolver string, and the current itinerary step; and it returns the updated message.
A reference implementation of the Execute method can be found in the RoutingService.cs file of the ESB.Itinerary.Services project, as shown in the following code.
public IBaseMessage ExecuteRoute(IPipelineContext context, IBaseMessage msg, string resolverString)
{
if (context == null)
throw new ArgumentNullException("context");
if (msg == null)
throw new ArgumentNullException("msg");
if (string.IsNullOrEmpty(resolverString))
throw new ArgumentException(Properties.Resources.ArgumentStringRequired, "resolverString");
try
{
ResolverInfo info = ResolverMgr.GetResolverInfo(ResolutionType.Endpoint, resolverString);
if (!info.Success)
throw new RoutingException(Properties.Resources.ResolverStringInvalid, resolverString);
// Resolve configuration for routing.
Dictionary<string, string> resolverDictionary = ResolverMgr.Resolve(info, msg, context);
if (string.IsNullOrEmpty(resolverDictionary["Resolver.TransportLocation"]))
throw new RoutingException(Properties.Resources.TransportLocationNotResolved, resolverString);
AdapterMgr.SetEndpoint(resolverDictionary, msg.Context);
return msg;
}
catch (System.Exception ex)
{
EventLogger.Write(MethodInfo.GetCurrentMethod(), ex);
throw;
}
}
To implement a custom itinerary service for messaging
Create an assembly with a class that derives from IMessagingService; in the Execute method, include all logic necessary to make modifications to the message or the message context (if any).
Add an entry in the itineraryServices section of the Esb.config file for your service by adding an <itineraryService> element with a GUID as the id attribute, the name of the service as the name attribute, the fully qualified name of the class as the type attribute, Messaging as the scope attribute, and the allowed stage (for example, OnRampReceive, OnRampSend, OffRampSend, OffRampReceive, AllSend, AllReceive, or All) as the stage attribute.
Register the new assembly in the global assembly cache.