BizTalk Custom Adapters
BizTalk Custom Adapters
Luigi Pampaloni
BizTalk Solutions Architect
LPYSoft Ltd
Content of the presentation
• First part
– BizTalk Interfaces to be implemented
• Second part
– SimpleHTTPAdapter documentation
2
BizTalk adapters
Aspect Options
Communication • Receive
• One-way Submit
Direction • Request – Response
• Request – Response time-outs
• Transmit
• One-way Send
• Solicit – Response
Adapter "code" • In-process – the adapter is created within BizTalk host process. All transmitting
hosted adapters are in-process
• Isolated – the receive adapter is created in an isolated host (external process i.e.
w3wp.exe) which is not part of the BizTalk runtime. A classic example is an http
receive adapter. The actual message is received while being in the IIS worker
process boundary
Port Binding • Static – the target location for send/receive is preconfigured
• Dynamic – the target location can be determined in runtime
Adapter • Asynchronous adapter – the adapter is able to send messages without holding
Capabilities the BizTalk send thread. Messages are sent on the adapter thread (relevant for
transmitting adapters)
• Transactional adapter – support for transactional send/receive of messages
• Batch support – the adapter supports receiving and transmitting batch of
messages
Design-time • Property browser – defines a list of properties and uses the std property dialog
• Metadata wizard – used to generate or import items (i.e. schemas) from an app
• Static – The wizard provides a standard default hierarchical tree structure
• Dynamic – The adapter provides a custom UI
3
Adapter components
• Design-time component
• Run-time component
– Receive adapter
– Send adapter
• Adapter registration
4
Design-time components
• Property browser. Adapter properties for a send or receive port, or a send or receive
handler, are configured through their Properties menu by using the BizTalk Server
Administration console. During configuration of these artifacts the adapter (transport)
is selected and its properties are configured by using a property browser. Applicable
properties are displayed through a schema with a set name. The adapter implements
the IAdapterConfig interface to locate and load the appropriate schema to expose
specific properties in the property browser. The IAdapterConfigValidation
interface is used to validate those entries and make any final modifications to the
values before saving the configuration data.
• Add Adapter Metadata Wizard. In the case of application and database adapters, you
may need to import supporting schemas that describe message types and port types
that the adapter needs in the BizTalk project in Visual Studio. Or sometimes there is
the need to consume services provided by the adapter. The Add Adapter Metadata
Wizard enables you to view services that an adapter supports and import the related
message types and port types into your project. This process is known as "metadata
harvesting." As an adapter developer you create an XML file describing those services
and expose it to the wizard at design time through either the IStaticAdapterConfig
or IDynamicAdapterConfig interface, with the following results:
– Static adapter. The wizard provides a standard default hierarchical tree structure with which to display the adapter's services. A
static adapter is defined as an adapter that uses the standard tree user interface (UI) provided by the wizard. Use the
IStaticAdapterConfig.GetServiceOrganization and GetServiceDescription methods to allow selected services to be added
to the BizTalk project. This is the simplest configuration option for an adapter developer, but the tradeoff is rigidity of the display
format
– Dynamic adapter. If the basic service selection UI provided by the wizard is not flexible enough meet your UI needs you can
create a custom UI that is dynamically displayed by the wizard. Use the IDynamicAdapterConfig.DisplayUI method to display
the custom UI to allow selection of services to be added to a BizTalk project
5
IAdapterConfig
• IAdapterConfig defines two methods, GetConfigSchema and
GetSchema. Based on the value of the ConfigType parameter,
GetConfigSchema must return the appropriate XSD which defines the
configuration properties. The schema will be validated against the
BizTalkAdapterFramework.xsd
• Under Microsoft.BizTalk.Adapter.Framework namespace
• Two methods must be implemented:
– string GetConfigSchema (ConfigType configType)
Get a schema representing the configuration properties of the adapter. Potentially, a receive handler, a
send handler, a receive location, and a send port could all have different schemas that define different
properties, in which case four different schemas would be needed
• Parameters
– configType
» The target usage of the configuration specification
(One of ReceiveHandler, ReceiveLocation, TransmitHandler, TransmitLocation)
• Return Value
– A string containing the schema that represents the configuration properties (XSD) or null if the configType type
is not supported
– Result GetSchema (string uri, string namespaceName, out string fileLocation)
Get the location of schema files that need to be imported into the BizTalk project
• Parameters
– uri
» A string containing the URI uniquely identifying the schema.
– namespaceName
» A string containing the namespace of the schema.
– fileLocation
» A string containing the XSD schema content.
• Return Value
– One of the Result values: Back, Cancel, Continue, Exit, Fail
6
IAdapterConfig sequence diagram
• GetConfigSchema must return the appropriate XSD which defines the configuration properties.
The schema will be validated against the BizTalkAdapterFramework.xsd
• GetSchema is called if there are any import nodes in the WSDL files returned by the adapter
during setup using the Adapter Wizard as a way to be able to import necessary schemas into the
BizTalk project but don't get confused by the name of the return parameter as defined by the
interface (fileLocation), the return should be the actual string representation of the schema and
will be validated against the BizTalkAdapterFramework schema
GetConfigSchema()
• Note: The GetSchema is called just when a WSDL is returned by the GetConfigSchema with an
import of an external schema (probably is not called when implement just the IAdapterConfig
interface)
7
IAdapterConfig configuration
public enum ConfigType
{
ReceiveLocation = 0,
TransmitLocation = 1,
ReceiveHandler = 2,
TransmitHandler = 3
public interface IAdapterConfig }
{
string GetConfigSchema( ConfigType cfgType);
}
XSD
8
IAdapterConfig sample implementation
public string GetConfigSchema(ConfigType type)
{
switch (type)
{
case ConfigType.ReceiveHandler:
return GetResource("ReceiveHandler.xsd");
case ConfigType.ReceiveLocation:
return GetResource("ReceiveLocation.xsd");
case ConfigType.TransmitHandler:
return GetResource("TransmitHandler.xsd");
case ConfigType.TransmitLocation:
return GetResource("TransmitLocation.xsd");
default:
return null;
}
}
9
IAdapterConfig sample schema
• Below a schema which defines a PropertyName as a property of type string
10
IAdapterConfigValidation
• IAdapterConfigValidation defines a single method,
ValidateConfiguration. This method will be called
when saving the configuration for any one of the four
configuration types
• Under Microsoft.BizTalk.Adapter.Framework namespace
• A method must be implemented:
– string ValidateConfiguration ( ConfigType configType, string configuration )
Validates the adapter configuration information
• Parameters
– configType
» One of the ConfigType values.
(One of ReceiveHandler, ReceiveLocation, TransmitHandler, TransmitLocation)
– configuration
» A string containing the xml instance that the adapter can load into an
XmlDocument instance.
• Return Value
– A string containing the xml instance configuration information, corrected if
necessary
– Throw an exception to notify wrong parameters specified on the property page
11
IAdapterConfigValidation sample impl.
public string ValidateConfiguration(ConfigType configType, string xmlInstance)
{
string validXml = String.Empty;
switch (configType)
{
case ConfigType.ReceiveHandler:
validXml = ValidateReceiveHandler(xmlInstance);
break;
case ConfigType.ReceiveLocation:
validXml = ValidateReceiveLocation(xmlInstance);
break;
case ConfigType.TransmitHandler:
validXml = ValidateTransmitHandler(xmlInstance);
break;
case ConfigType.TransmitLocation:
validXml = ValidateTransmitLocation(xmlInstance);
break;
}
return validXml;
}
12
NOTE: Address (URI) is mandatory
• The Address (URI) property is mandatory and read only
on BTS
– To set the Address (URI) property add a property called URI (browseable=false)
13
IAdapterInfo
• IAdapterInfo defines a single method, GetHelpString which should
return a link to the help file associated with the configuration. This method
will be called when the help button is clicked while viewing the custom
adapter configuration property sheet for any one of the four configuration
types
14
IStaticAdapterConfig
• The UI for the IStaticAdapterConfig interface will be generated based on
the xml returned by a call to the GetServiceDescription method (the
return will be validated against the BizTalkAdapterFramework schema and
will be used to generate a tree-view of the "services" the adapter provides
• Under Microsoft.BizTalk.Adapter.Framework namespace
• Two methods must be implemented
– string GetServiceOrganization ( IPropertyBag endpointConfiguration, string nodeIdentifier )
Get an XML representing the way the adapter organizes its services. This tree is used to generate the
service organization tree that is displayed to the user in the Add Adapter Wizard
• Parameters
– endpointConfiguration
– nodeIdentifier
» The name of the node. The Adapter Framework passes null to request the root of the service
organization hierarchy and the name of a node to request the hierarchy under an expandable tree node.
• Return Value
– A string containing XML that represents the way the adapter organizes its services
– string[] GetServiceDescription ( string[] wsdlReferences )
Gets an array of Web Service Description Languages (WSDL), based on the unique WSDL references
specified in the returned XML of the GetServiceOrganization method
• Parameters
– wsdlReferences
» An array of string with the WSDL references (as obtained from the Service Organization XML). Each input
string is derived from the XML provided from the GetServiceOrganization call.
• Return Value
– An array of string of WSDLs. Each output string should contain the WSDL content corresponding to the WSDL
reference in the input parameter
15
IStaticAdapterConfig sequence diagram
• The GetServiceOrganization is called to get the hierarchical structure of the
services
• The service description (as WSDL format) is requested for each service
selected on the UI
• For each import defined on the WSDL the GetSchema is called to retrieve
the external schema
GetServiceOrganization()
GetServiceDescription()
GetSchema()
External Schema
16
IStaticAdapterConfig configuration
XSDs
17
IStaticAdapterConfig sample implementation
public string GetServiceOrganization(IPropertyBag endPointConfiguration, string NodeIdentifier)
{
// Simple implementation, assuming the TreeView xml instance is on the filesystem
string result = "";
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Filter = "Service description files (*.xml)|*.xml|All files (*.*)|*.*";
if (fileDialog.ShowDialog() == DialogResult.OK)
{
using (TextReader tr = new StreamReader(fileDialog.FileName))
{
result = tr.ReadToEnd();
tr.Close();
}
}
return result;
}
18
IStaticAdapterConfig sample XML & UI
• Service Organization sample XML
<?xml version="1.0" encoding="utf-8" ?>
<CategoryTree>
<DisplayName>Services Organization</DisplayName>
<DisplayDescription>An organization of application services</DisplayDescription>
<CategoryTreeNode>
<DisplayName>Health Care</DisplayName>
<Description>Services under Health Care</Description>
<CategoryTreeNode>
<DisplayName>Administrative</DisplayName>
<Description>Administrative Health Care Svc</Description>
<ServiceTreeNode>
<DisplayName>Eligibility</DisplayName>
<Description>Eligibility Verification Tx</Description>
<WSDLReference>ANSI X 12 270</WSDLReference>
</ServiceTreeNode>
</CategoryTreeNode>
</CategoryTreeNode>
<CategoryTreeNode>
<DisplayName>Manufacturing</DisplayName>
<Description>Manufacturing Services</Description>
<CategoryTreeNode>
<DisplayName>Inventory</DisplayName>
<Description>Inventory Services</Description>
<ServiceTreeNode>
<DisplayName>Requisition</DisplayName>
<Description>Requisition</Description>
<WSDLReference>RequisitionService</WSDLReference>
</ServiceTreeNode>
</CategoryTreeNode>
</CategoryTreeNode>
</CategoryTree>
19
IDynamicAdapterConfig
• The UI for the IDynamicAdapterConfig interface is
defined by the developer and should be loaded in the
DisplayUI method which will be called by the wizard
– Result DisplayUI ( IPropertyBag endpointConfiguration, IWin32Window owner,
out string[] serviceDescriptionFiles )
Displays the user interface for the custom adapter, enabling the user to import
the services descriptions that are returned to BizTalk and then added to the
BizTalk project
• Parameters
– endpointConfiguration
– owner
» An IWin32Window containing the handle to the parent window.
– serviceDescriptionFiles
» An array of string with the Web Service Description Languages (WSDL)
references (as obtained from the Service Organization XML). Each string
should be a valid WSDL file (with root element <definitions>). The Adapter
Framework reads the strings into instances of the ServiceDescription
class.
• Return Value
– An array of string of WSDLs
20
IDynamicAdapterConfig sequence diagram
• The DisplayUI open a custom form. An array of WSDLs is returned by the
UI
• For each import defined on the WSDL the GetSchema is called to retrieve
the external schema
DisplayUI()
GetSchema()
External Schema
21
IDynamicAdapterConfig configuration
GetDisplayUI Display
Custom UI
WSDLs
GetSchema
XSDs
22
IDynamicAdapterConfig sample implementation
• DisplayUI sample
23
Run-time components
• Messages
• Message Engine
• Receive adapter
• Transmit adapter
24
Messages
• A message (IBaseMessage) has one or more message parts represented
by the IBaseMessagePart interface. Each message part has a reference
to its data through an IStream interface pointer. The context of a message
is represented by its IBaseMessageContext interface. The following
figure illustrates the BizTalk message object model
25
Message Engine
• The messaging engine has three public interfaces used
by adapters:
– IBTTransportProxy Adapters always talk to the messaging engine via their
own Transport Proxy. The Transport Proxy is used to create batches, get the
message factory, and register isolated receivers with the engine
– IBTTransportBatch The interface exposed by the messaging engine's batch.
Work done against the engine is performed using a batch; batches are processed
asynchronously.
– IBTDTCCommitConfirm Adapters using DTC transactions on batches must
notify the engine of the outcome of the transaction using this interface
26
Message Engine – receive message flow
1. The Adapter creates a new message, connecting the
data stream to the message.
27
Adapter load and initialisation
• When the BizTalk service starts, all receive adapters are
instantiated, as long as they have one or more configured and
active receive locations
• By default a send adapter is not instantiated until the Messaging
Engine removes from the queue the first message to be sent by
using that send adapter
• The following figure shows the logic for creating adapters:
28
Receive adapter interfaces
• Below a list of mandatory/optional interfaces to be
implemented by the receive adapter
29
Receive adapter initialisation
• Immediately after a receive adapter is instantiated it is initialized by the Messaging Engine, the
engine calls QueryInteraface for IBTTransportControl. It then calls
IBTTransportControl.Initialize passing in the adapter's transport proxy, which the adapter
persists in a member variable. Next the engine calls QueryInterface for IPersistPropertyBag.
This is an optional interface; if the adapter implements it, the handler configuration is passed to
the adapter in the Load method call. The final stage of initializing a receive adapter involves
passing the endpoint configuration to the adapter. During this phase the engine calls
IBTTransportConfig.AddReceiveEndpoint once for each active endpoint, passing in the URI
for the endpoint, the adapter specific configuration for the endpoint, and the BizTalk
configuration for that endpoint
30
In-process receive adapter initialisation
• The Messaging Engine creates an instance of an adapter, initializes it, and
sets the configuration of receive locations. The Messaging Engine passes a
property bag to an adapter on the AddReceiveEndpoint method call. The
property bag contains the configuration for the receive location and receive
handler. The configuration is stored in the database in the form of an XML-
styled property bag. The Messaging Engine reads the XML and rehydrates a
property bag from the XML. After at least one endpoint (receive location) is
added, the adapter can start submitting messages
31
Isolated receive adapter initialisation
• After the adapter has successfully registered with the transport proxy, the
Messaging Engine passes the configuration information and the other
receive locations back to the adapter by calling the Load method of the
IPersistPropertyBag interface and the AddReceiveEndpoint method of
the IBTTransportConfig interface respectively
32
Receive adapter operations
• Receive adapters can perform the following operations:
– One-way submit: void SubmitMessage(IBaseMessage msg). After
receiving a message from a receive port, the adapter submits it to BizTalk Server
to be processed by a subscribing orchestration or send port
– Suspend: void MoveToSuspendQ(IBaseMessage msg). When the adapter
determines a parsing, transmission, serialization, or other applicable failure has
occurred after submission, it moves the message to the Suspended queue
– Submit request: void SubmitRequestMessage(IBaseMessage
requestMsg, string correlationToken, bool firstResponseOnly,
DateTime expirationTime, IBTTransmitter responseCallback). A receive
adapter submits an incoming message to BizTalk Server in a request-response
pair. After BizTalk Server successfully processes this request message, it sends
the response to the adapter to transmit it to the specific endpoint
33
One-way batch receive
• A receive adapter obtains the batch from the transport proxy by calling the GetBatch method of the IBTTransportProxy interface. In its call to GetBatch the adapter
passes in a pointer to its IBTBatchCallback interface implementation.
• An adapter adds the messages one at a time into the batch by calling the SubmitMessage method of the IBTTransportBatch interface. If this is a two-way operation
such as solicit-response messaging, the SubmitResponseMessage method of this same interface is called to submit the response message.
• When all the messages have been added to the batch, the adapter calls the Done method of the IBTTransportBatch interface to submit the batch to the transport
proxy. Because receive adapters are asynchronous in nature, the adapter can immediately obtain a new batch and start submitting other messages after it calls Done.
• After the batch has been processed, the Messaging Engine invokes the adapter's BatchComplete callback method using the transport proxy to make the actual call. An
array of BTBatchOperationStatus objects containing the status of the submission is passed to the adapter. Each object corresponds to an operation type and contains
the overall status of the operation as well as the status for each message for which the operation was performed. The following sequence describes the actions the
adapter needs to perform to analyze the status of batch processing:
• Check the overall batch status HRESULT value passed as a parameter to the BatchComplete method. If it is a failure, it means that at least one of the operations in the
batch was unsuccessful. Therefore the submission of the entire batch as one entity failed. The adapter should then try to discover the offending message(s) and resubmit
as a batch only the ones that did not initially cause a failure.
If the overall batch status succeeded, it means that all the messages that were given to the transport proxy were persisted to disk. However, it does not mean that the
pipeline successfully processed all the messages. It is possible that messages that failed in the pipeline were suspended. For messages that fail in the pipeline, the overall
batch status returned is successful because the data was written to disk.
• Check the status for each operation type in the operationStatus parameter. If the status is S_OK, the submission for this operation succeeded and you do not need to
check the status any further. If the status is set to BTS_S_EPM_MESSAGE_SUSPENDED some of the messages were suspended.
BTS_S_EPM_SECURITY_CHECK_FAILED signifies that some messages failed authentication in an authentication-required receive port. If E_FAIL is returned, or any
HRESULT with a value that is less than zero, the message submission for this operation failed.
• Check the status of individual messages for the operation type. For the submit operation type, the status of each message is set to S_OK if the submission succeeded.
BTS_S_EPM_MESSAGE_SUSPENDED is returned if the message was suspended. BTS_S_EPM_SECURITY_CHECK_FAILED is returned if the message failed
authentication on a receive port that requires authentication. E_BTS_NO_SUBSCRIPTION comes back if there were no subscribers for the published message. If
E_FAIL is returned, or any HRESULT with a value that is less than zero, the message submission failed.
• Depending on your adapter, you may want to suspend messages that return E_FAIL or any failing HRESULT.
• The BatchComplete method needs to return either S_OK or E_FAIL to indicate the result of execution. If the BatchComplete method returns E_FAIL or any
negative HRESULT, the transport proxy logs an error.
34
One-way transactional batch receive
• A transactional receive adapter creates and passes a pointer to a Microsoft Distributed Transaction Coordinator
(MSDTC) transaction on the Done method of the IBTTransportBatch interface. This ensures that all batch
operations are performed in the scope of that specific transaction object. When the batch submission completes,
the adapter callback method commits or rolls back the transaction. Which action it takes depends upon the status
returned from the transport proxy, and possibly upon other transaction-related work that the adapter does that is
not visible to the transport proxy. The adapter determines whether the transaction failed or succeeded. The
adapter reports the result of the transaction (commit or rollback) back to the transport proxy by using the
DTCCommitConfirm method of the IBTDTCCommitConfirm interface. It passes in true for a successful
transaction or false for a failure
35
Request-response receive adapter
• The receive adapter receives incoming request messages. It obtains a batch from the transport proxy by calling the GetBatch method
of the IBTTransportProxy interface. In this call the adapter passes in a callback pointer to its implementation of the
IBTBatchCallBack.BatchComplete method.
• The adapter adds request messages into the batch by calling the SubmitRequestMessage method of the IBTTransportBatch
interface, once for each request message.
• When all the messages have been added, the adapter calls the Done method of the IBTTransportBatch interface, which submits the
batch to the Messaging Engine through the transport proxy.
• After the batch has been processed, the Messaging Engine invokes the adapter's IBTBatchCallBack.BatchComplete callback method
through the transport proxy. The status of the submission is passed to the adapter as an array of HRESULT values corresponding to
each message in the batch. If the batch fails, either in the pipeline or in the orchestration, the SOAP fault message is returned to the
adapter as a response.
• The incoming request messages may have orchestration subscribers. After the orchestration completes and the request message has
been processed, the Messaging Engine sends the response message through the transport proxy to the adapter by calling the adapter's
TransmitMessage method from the IBTTransmitter interface.
• The adapter sends a response message and deletes the original message from the MessageBox database.
36
IBaseComponent
• Three read only properties to be provided by the adapter
– String Name – Adapter name
– String Description – Adapter description
– String Version – Adapter version
37
IBTTransport
• Three read only properties to be provided by the adapter
– String TransportType
– Guid ClassID
38
IBTBatchCallBack
• BatchComplete
– Called by BTS once the message is received by the EPM
39
IBTTransportConfig
• AddReceiveEndPoint
– Called by BTS for each port bound to the adapter and started when the BTS
service instance starts
– Or
– When a port bound to the adapter is started
• RemoveReceiveEndPoint
– Called when a port is shut down
• UpdateEndPointConfig
– Called when the properties of the port are changed
40
IBTTransportControl
• Initialize
– Called by BTS when the BTS service starts
• Terminate
– Called by BTS when the BTS service is stopped
41
Transmit adapter interfaces
• Below the list of the mandatory/optional interfaces:
42
Transmit adapter initialisation
• When the Messaging Engine initializes a send adapter, it first performs a QueryInterface for
IPersistPropertyBag, which is an optional interface. If the adapter implements the interface, the handler
configuration is passed to the adapter in the Load method call. The adapter uses this information to ensure it is
configured correctly.
• The Messaging Engine performs a QueryInterface for IBTTransportControl, which is a mandatory interface.
• The engine calls IBTTransportControl.Initialize, passing in the transport proxy for the adapter.
• The Messaging Engine performs a QueryInterface for IBTTransmitter.
If the Messaging Engine discovers this interface, the adapter is treated as a batch-unaware transmitter.
If the Messaging Engine does not discover this interface, the Messaging Engine performs a QueryInterface for
IBTBatchTransmitter, discovery of which indicates that the adapter is a batch-aware transmitter.
If the Messaging Engine discovers neither of these interfaces, an error condition results, causing the initialization
to fail. The initialization fails if any mandatory interfaces are not discovered.
43
Transmit adapter operations
• Resubmit: void Resubmit(IBaseMessage msg, DateTime timeStamp). After a
transmission failure occurs on a message, an adapter resubmits it when appropriate. This is
called on a per-message basis. If a batch of messages was submitted unsuccessfully, the adapter
must determine the messages causing the failure, and resubmit the ones that did not cause the
batch to fail in separate calls to Resubmit. There is information at the end of this topic about
how to preserve message context property values when you call Resubmit.
• Move to Next Transport: void MoveToNextTransport(IBaseMessage msg). If a message
fails during a send operation and its retry attempts have been exhausted, the adapter can send
the message to the next configured transport for retransmission.
• Suspend: void MoveToSuspendQ(IBaseMessage msg). The adapter moves a failed send
message to the Suspended queue if no additional backup transport is configured. There is
information at the end of this topic about how to preserve message context property values when
you call Suspend.
• Delete: void DeleteMessage(IBaseMessage msg). The adapter deletes a message after
being notified by BizTalk Server of its successful transmission. Deleting a message tells BizTalk
Server that the adapter is finished with the message. Generally the SubmitResponse operation
is done in the same batch as its associated Delete operation.
• Submit Response: void SubmitResponseMessage(IBaseMessage solicitMsgSent,
IBaseMessage responseMsgToSubmit). The adapter submits a response to the batch to be
sent back to BizTalk Server. This operation includes the original message in the call along with
the response so that BizTalk Server can correlate them.
• Cancel Response: void CancelResponseMessages(string correlationToken). If the
sending of a response message needs to be canceled before the batch is submitted, the
CancelResponseMessages method is used, passing in the correlation token for the associated
response message to be deleted.
44
Transmit adapter synchronous send
• In a synchronous send, the adapter sends the message while blocking
TransmitMessage, and after successful transmission returns True
45
Transmit adapter asynchronous send
• The Messaging Engine uses the transport proxy to pass an outgoing message to a send adapter
by calling the TransmitMessage method of the IBTTransmitter interface.
• The adapter returns immediately from TransmitMessage after storing the message to be sent
to some internal queue, and returns False for bDeleteMessage. This tells the Messaging
Engine the message will be transmitted in an asynchronous manner.
• The adapter sends the message using its own thread pool.
• After the send operation completes, the adapter deletes the original message from the
MessageBox database. It obtains a batch from the Messaging Engine using the
IBTTransportBatch.GetBatch method of the transport proxy, and then calls DeleteMessage.
46
Transmit adapter synchronous batch send
• Batch-aware adapters may send messages synchronously or asynchronously, and
may perform transacted send operations. To send batches of messages, a send
adapter must implement the following interfaces:
• For the synchronous batch send, the Messaging Engine gets a batch from the adapter
and adds messages to be transmitted to that batch. The Messaging Engine adds each
message to the batch and sends the messages only when it calls the Done method
on the batch. The adapter returns True for bDeleteMessage for each message that
it intends to transmit synchronously. The adapter should save message data, as
opposed to a message pointer, in its TransmitMessage implementation. This is
because the message pointer is no longer valid after True is returned, and should
not be used or cached for later use
47
Transmit adapter asynchronous batch send
• For the asynchronous batch send, the Messaging Engine gets a
batch from the adapter and adds messages to be transmitted to
that batch. The messages are only sent when the Messaging Engine
calls the Done method on the batch. The adapter returns False for
each message that it intends to transmit asynchronously. The
adapter then gets a batch from the adapter proxy and deletes those
messages that it successfully transmitted
48
Transmit adapter tx asynchronous batch send
• An adapter creates an MSDTC transaction and returns a pointer to that object in the call to the BeginBatch
method of the IBTTransmitterBatch interface. The Messaging Engine calls this method to obtain a batch with
which it posts outgoing messages to the send adapter. When the adapter finishes the send operation and
commits or rolls back a transaction, it notifies the Messaging Engine of the result of the transaction by using the
DTCCommitConfirm method of the IBTDTCCommitConfirm interface
49
Transmit adapter solicit response
• After the adapter sends a solicit message, it receives back a response message from that destination server. It then obtains a batch from
the transport proxy.
• The adapter adds the response message to the batch by calling IBTTransportProxy::SubmitResponseMessage.
• The adapter submits the batch by calling IBTTransportProxy::Done passing in a pointer to its IBTBatchComplete interface for the
callback from the Messaging Engine.
• The Messaging Engine calls the adapter's IBTBatchCallBack::BatchComplete callback method using the transport proxy notifying it
of the result of submission operation.
50
IBTTransmitter
• Initialize
• Terminate
• TransmitMessage
– Called by BizTalk when a message needs to be sent
– It returns a Boolean
• If the return value is True BizTalk remove the message from the
MessageBox
• If the return value is False you have to write the code to remove the
message from the MessageBox
– If the send function is called asynchronously it is better to return False then
process the message in a separate thread and then remove the message from
the MessageBox
– If the port is a dynamic port the message context property AdapterConfig
(containing the port properties) is not present. You need to access the
OutboundTransportLocation property with the following namespace
http://schemas.microsoft.com/BizTalk/2003/system-properties in order to
retrieve the dynamic properties of the port
51
Adapter registration
• The information about adapters must be registered in
the registry and the BizTalk Management database
• Information such as an adapter's alias, receive hander,
receive location, and transport type is called metadata
– These metadata entries can be created manually during the development phase
in the form of a registry file
– Alternatively, you can run the Adapter Registration Wizard
(AdapterRegistryWizard.exe) SDK utility to generate a registry file for your
custom adapter
52
Report errors to BizTalk
• If you are suspending a message, you must provide
failure information to BizTalk Server from the previous
message context. BizTalk Server provides error reporting
capabilities using the SetErrorInfo method on both the
IBaseMessage and ITransportProxy interfaces. You
can report errors as follows:
– When a failure occurs while processing a message, set the exception using
SetErrorInfo(Exception e) on the message (IBaseMessage) to be
suspended. This allows the engine to preserve the error with the message for
later diagnosis and logs it to the event log to alert the administrator.
– If you encounter an error during initialization or internal bookkeeping (not during
message processing) you should call SetErrorInfo(Exception e) on the
ITransportProxy pointer that was passed to you during initialization. If your
adapter is based on the BaseAdapter implementation, you should always have
access to this pointer. Otherwise, you should be certain that you cache it.
53
Adapters registry entries
• Registry entries
– Location
[HKEY_CLASSES_ROOT\CLSID\{%uuid of custom transport%}\BizTalk]
@="BizTalk"
– Adapter type name
"TransportType"="MyTransportAdapter"
– Adapter constraints define the adapter's capabilities
"Constraints"=dword:00003C0b
54
Adapters registry entries
– Each adapter must define a namespace for its properties
"PropertyNameSpace"="namespace"
– Each adapter may have a set of prefixes that uniquely identify the adapter type
within BizTalk Server. This allows resolution of the correct transport type when
sending a message through a dynamic send port
"AliasesXML"="<AdapterAliasList><AdapterAlias>sample://</AdapterAlias></A
dapterAliasList>"
– The adapter must have configuration property pages to configure its receive
locations and send ports. Each adapter registers its property pages by specifying
their respective class IDs
"InboundProtocol_PageProv"="{%CLSID for inbound protocol prop page%}"
"OutboundProtocol_PageProv"="{%CLSID for outbound protocol prop page%}"
"ReceiveLocation_PageProv"="{%CLSID for receive location prop page%}"
"TransmitLocation_PageProv"="{%CLSID for transmit location prop page%}"
If the adapter uses the Adapter Framework's user interface for property page
generation, it must specify the following values for the registry keys
"InboundProtocol_PageProv"="{2DE93EE6-CB01-4007-93E9-C3D71689A281}"
"OutboundProtocol_PageProv"="{2DE93EE6-CB01-4007-93E9-C3D71689A283}"
"ReceiveLocation_PageProv"="{2DE93EE6-CB01-4007-93E9-C3D71689A280}"
"TransmitLocation_PageProv"="{2DE93EE6-CB01-4007-93E9-C3D71689A282}"
55
Adapters registry entries
– The adapter registers its runtime components by specifying their class IDs (for COM and
.NET), type names, and assembly paths (for .NET) for receive and send runtime components
"OutboundEngineCLSID"="{%CLSID of outbound transport%}"
"InboundEngineCLSID"="{%CLSID of inbound transport%}"
"InboundTypeName"="BizTalk.Samples.Adapters.MyReceiver"
"OutboundTypeName"="BizTalk.Samples.Adapters.MyTransmitter"
"InboundAssemblyPath"="C:\Program Files\MyTransport.dll"
"OutboundAssemblyPath"="C:\Program Files\MyTransport.dll"
– The adapter needs to register its properties with the BizTalk Server SSO database to be able
to store and retrieve the properties at design time and run time
ReceiveHandlerPropertiesXML
ReceiveLocationPropertiesXML
SendHandlerPropertiesXML
SendLocationPropertiesXML
– The adapter must be registered under its Implemented Categories attribute in the registry as
a transport provider. This attribute identifies its characteristics to consumers of the adapter
[HKEY_CLASSES_ROOT\CLSID\{%uuid of custom transport%}\Implemented Categories]
[HKEY_CLASSES_ROOT\CLSID\{%uuid of custom transport%}\Implemented
Categories\{7F46FC3E-3C2C-405B-A47F-8D17942BA8F9}]
56
Registry file sample
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\CLSID\{62018D08-281A-415b-A6D3-6172E3762867}]
@="Static DotNetFile Adapter"
"AppID"="{12A6EBAA-CF68-4B58-B36E-A5A19B22C04E}"
[HKEY_CLASSES_ROOT\CLSID\{62018D08-281A-415b-A6D3-6172E3762867}\BizTalk]
@="BizTalk"
"TransportType"="Static DotNetFile"
"Constraints"=dword:00003C0b
"InboundProtocol_PageProv"="{2DE93EE6-CB01-4007-93E9-C3D71689A281}"
"OutboundProtocol_PageProv"="{2DE93EE6-CB 01-4007-93E9-C3D71689A283}"
"ReceiveLocation_PageProv"="{2DE93EE6-CB01-4007-93E9-C3D71689 A280}"
"TransmitLocation_PageProv"="{2DE93EE6-CB01-4007-93E9-C3D71689A282}"
"InboundEngineCLSID"="{3D4B599E-2202-4bbb-9FC6-7ACA3906E5DE}"
"InboundTypeName"="Microsoft.BizTalk.SDKSamples.Adapters.DotNetFileReceiver"
"InboundAssemblyPath"="C:\\Program Files\\Microsoft BizTalk Server 2006\\SDK\\Samples\\AdaptersDevelopment\\File
Adapter\\Runtime\\bin\\Debug\\Microsoft.BizTalk.SDKSamples.Adapters.DotNetFile.Runtime.dll"
"OutboundEngineCLSID"="{024DB758-AAF9-415e-A121-4AC245DD49EC}"
"OutboundTypeName"="Microsoft.BizTalk.SDKSamples.Adapters.DotNetFileTransmitter"
"OutboundAssemblyPath"="C:\\Program Files\\Microsoft BizTalk Server 2006\\SDK\\Samples\\AdaptersDevelopment\\File
Adapter\\Runtime\\bin\\Debug\\Microsoft.BizTalk.SDKSamples.Adapters.DotNetFile.Runtime.dll"
"AdapterMgmtTypeName"="Microsoft.BizTalk.SDKSamples.Adapters.Designtime.StaticAdapterManagement"
"AdapterMgmtAssemblyPath"="C:\\Program Files\\Microsoft BizTalk Server 2006\\SDK\\Samples\\AdaptersDevelopment\\File
Adapter\\Design Time\\Adapter Management\\bin\\Debug\\Microsoft.BizTalk.SDKSamples.Adapters.DotNetFile.Designtime.dll"
"PropertyNameSpace"="http://schemas.microsoft.com/BizTalk/2003/SDK_Samples/Messaging/Transports/dotnetfile-properties"
"AliasesXML"="<AdapterAliasList><AdapterAlias>DotNetFILE://</AdapterAlias></AdapterAliasList>"
"ReceiveHandlerPropertiesXML"="<CustomProps><AdapterConfig vt=\"8\"/></CustomProps>"
"SendHandlerPropertiesXML"="<CustomProps><AdapterConfig vt=\"8\"/></CustomProps>"
"ReceiveLocationPropertiesXML"="<CustomProps><AdapterConfig vt=\"8\"/></CustomProps>"
"SendLocationPropertiesXML"="<CustomProps><AdapterConfig vt=\"8\"/></CustomProps>"
[HKEY_CLASSES_ROOT\CLSID\{62018D08-281A-415b-A6D3-6172E3762867}\Implemented Categories]
[HKEY_CLASSES_ROOT\CLSID\{62018D08-281A-415b-A6D3-6172E3762867}\Implemented Categories\{7F46FC3E-3C2C-405B-A47F-8D17942BA8F9}]
57
Registry entries
• For 32 bit adapters the keys are stored in
– HKEY_CLASSES_ROOT\CLSID
58
Adapter registry wizard
• AdapterRegistryWizard.exe
– The wizard (under the SDK\utilities) helps you to create the registry entries for a
custom adapter
– Generates a .reg file
59
Best practices
• Split the adapter into three components
– So BTS at run-time needs just to load the receive and transmit
60
ESB Toolkit
• The adapter implemented cannot be called natively from
the ESB Toolkit from a STATIC or BRE resolver
• The configuration properties specified on the resolver
need to be translated into message context properties
through an Adapter Provider
• Sample of and Adapter Provider is attached with the
source code
61
Static Resolver
• The Resolver may use a Static port like in the screenshot
64
Add a class with the following code
• Public class deriving from BaseAdapterProvider
– public class AdapterProvider : BaseAdapterProvider
65
SetEndpoint
• Calls the base SetEndpoint and retrieve the base
transport properties
– base.SetEndpoint(resolverDictionary, message);
66
SetEndpoint
• Gets the endpoint config
– string endpointConfig = resolverDictionary["Resolver.EndpointConfig"];
67
SetEndpoint properties parsing
• The implementation just splits by “;” to get key-value
pairs then splits by “=” to separate the key from the
value
• Simple to read and maintain but your configuration
cannot contain ; or = as values (i.e. your password
cannot contain = or any base64 encoded string)
• Better implementation is to embed an XML fragment and
parse using the DOM
68
How to deploy the Adapter Provider
• The deployment requires:
– On all the BizTalk nodes, GAC the Adapter Provider dll
– Edit the esb.config file to add the following XML fragment under
adapterProviders:
– <adapterProvider
– name="SimpleHTTP"
– type="HTTPAdapterESBProvider.AdapterProvider,
HTTPAdapterESBProvider, Version=1.0.0.0, Culture=neutral,
PublicKeyToken= "
– moniker="SimpleHTTP" />
69
How to call the adapter provider
• Now you can call the Off-Ramp on your Itinerary and the
dynamic port transmission detail can be stored in a rule
70
The sample adapter (SimpleHTTPAdapter)
Introduction
• The adapter implement a simple HTTP adapter
– In-Process adapter (hosted by BizTalk service)
• Other
– The adapter is asynchronous
– The adapter is not transactional
– The adapter is not batching (it sends/receives messages straight to/from the
EPM)
– Implements a property browser at design time
72
Configuration properties
• Receiver
– Port Number: the TCP/IP port number used by the HTTP listener
• Each receive port needs a different number
• Transmitter
– Url: The url to post the body part of the message
73
Project folder structure
• SimpleHTTPAdapter
– Source code for the adapter
• TestApp
– Console application to test some methods of the adapter
• HttpRequestor
– Windows application to post strings to urls
• BizTalkTestApp
– Orchestrations to test the adapter
• TestWeb
– A web application to test the send adapter
• FileOut
– Folder used to dump messages from the orchestrations
74
SimpleHTTPAdapter
• Created a new Class Library
– SimpleHTTPAdapter
• Folders
– ConfigSchemas: contains the schemas for the BTS property page
– Management: contains the source code for the configuration interfaces
– Receiver: contains the source code for the receiver
– Transmitter: contains the source code for the transmitter
75
Management implementation
• SimpleHTTPAdapterManagement.cs
– SimpleHTTPAdapterManagement class which implements
• IAdapterConfig – to return the schemas for the BTS property page
• IAdapterConfigValidation – to check validity of the configuration and to add
the URI (Address URI)
• ConfigSchemas
– Contains the schema files which are embedded resources
76
Receiver implementation
• SimpleHTTPAdapterReceiver.cs
– SimpleHTTPAdapterReceiver class which implements
• IBaseComponent – the 3 props implemented
• IBTTransport – the 2 props implemented
• IBTTransportControl – To initialize and terminate the adapter
• IBTTransportConfig – To start and stop the HTTP listener for each receive
port
• ReceiverBase.cs
– ReceiverBase class
– Defines the Start and Stop abstract methods
– Provides a SubmitMessage, SubmitRequestMessage and ExtractConfigProperty
methods for the derived class
• HttpReceiver.cs
– HttpReceiver class which implements
• ReceiverBase – implements the Start and Stop methods
• IBTTransmitter – implemented for the solicit-response ports
• IBTBatchCallBack – BTS call back delegate
77
Transmitter implementation
• SimpleHTTPAdapterTransmitter.cs
– SimpleHTTPAdapterTransmitter class which implements
• IBaseComponent – the 3 props implemented
• IBTTransport – the 2 props implemented
• IBTTransmitter – To send the message to the destination
• TransmitterBase.cs
– TransmitterBase
• Defines the TransmitMessage abstract method
• Provides CreateMessage and ExtractConfigProperty methods to the derived
classes
• HttpTransmitter.cs
– HttpTransmitter class which implements
• TransmitterBase – Implements the TransmitMessage
• IBTBatchCallBack – BTS call back delegate
78
Other classes
• AdapterStream.cs
– AdapterStream class
• Implements a seekable stream
• Derives from MemoryStream class
• Implement a static method to clone streams
• Constants.cs
– Constants class
• List of constants used throughout the code
• ControlledTermination.cs
– ControlledTermination class
• Semaphore used to control the adapter termination. The adapter when BTS
calls the terminate method is waiting until all the messages are submitted to
BTS
79
Exception Handling
• During the initialization and termination phases:
– Called the SetErrorInfo of the TransportProxy object to inform BTS of the error
Sample code of the above implementation is on the catch block of the transmitter
80
HttpRequestor test application
URL to post
Post body
Response
Error
81
BizTalkTestApp test application
• One Schema (Namespace http://test)
– Root element r one child a
• <r xmlns=“http://test”><a>some text</a></r>
• Three orchestrations
– BizTalk Orchestration1.odx
• Receive a message from a One-Way receive port
• Send the message received to a file drop port
• Send the message received to a One-Way send port
– BizTalk Orchestration2.odx
• Receive a message from a Request-Response port
• Send the message received to a file drop port
– BizTalk Orchestration3.odx
• Receive a message from a One-Way receive port
• Send the message received to a Solicit-Response send port
• Send the message received (from the solicit-response port) to a file drop
port
82
Bindings
• BizTalk Orchestration1.odx
– SimpleHTTP_OneWay_Receive: To a SimpleHTTPAdapter (Listening on port
8080)
– File_Send port: To a folder
– SimpleHTTP_OneWay_Send: To a SimpleHTTPAdapter
(http://localhost/TestWeb/Default.aspx)
• BizTalk Orchestration2.odx
– SimpleHTTP_TwoWay_Receive: To a SimpleHTTPAdapter (Listening on port
8888)
– File_Send port: To a folder
• BizTalk Orchestration3.odx
– SimpleHTTP_OneWay_Receive: To a SimpleHTTPAdapter (Listening on port
9999)
– SimpleHTTP_TwoWay: To a SimpleHTTPAdapter
(http://localhost/TestWeb/Default.aspx)
– File_Send port: To a folder
83
TestWeb test application
• http://localhost/TestWeb/Default.aspx
– On the OnLoad
• Reads the content posted by the client and trace it (OutputDebugString)
• Returns an XML message
84
How to deploy
• Adapter
– Open the .reg file and change the path of the assemblies
– Register the .reg
– Add the adapter to the adapter list (from the BTS Admin)
– Restart BTS service
• BizTalkTestApp
– Deploy the solution
– Bind the ports as per specification
– Start the orchestrations
85
How to test
• If you want to test the initialize methods
– Disable all the ports bound to the adapter
– Restart BTS
– Attach VS to the BTS process
– Set the breakpoints
– Enable the ports
– Now disable the ports and stop the BTS service to test the termination source
code
86
How to test
• If you want to test the One-Way send port
– Enable the port and the BTS service
– Start the BizTalk Orchestration 1
– Attach VS to the BTS process
– Set the breakpoints
– Use the HTTPRequestor to post a message (http://localhost:8080)
– The result is the message posted saved as file in the file drop location
– On the output window of VS you can see the dump of the message (done by the
default.aspx page)
• The entry starts with the following string: Received from TestWeb web app:
87
How to test
• If you want to test the request-response receive port
– Enable the port and the BTS service
– Start the BizTalk Orchestration 2
– Attach VS to the BTS process
– Set the breakpoints
– Use the HTTPRequestor to post a message (http://localhost:8888)
– The orchestration is responding with the same message so you can see the same
message you sent as request on the response text box of the HTTPRequestor
– The result is the message posted saved as file in the file drop location
• If you want to test the solicit-response port
– Enable the port and the BTS service
– Start the BizTalk Orchestration 3
– Attach VS to the BTS process
– Set the breakpoints
– Use the HTTPRequestor to post a message (http://localhost:9999)
– The solicit-response post the message to the testweb web application
– The result is the message returned by testweb and saved as file in the file drop
location
88
How to test
• If you want to test the dynamic port
– Enable the port and the BTS service
– Start the BizTalk Orchestration 4
– Attach VS to the BTS process
– Set the breakpoints
– Use the HTTPRequestor to post a message (http://localhost:9999)
– The solicit-response post the message to the testweb web application
– The result is the message returned by testweb and saved as file in the
file drop location
89
Assembly file locked when loaded
• If the assembly is locked by the client you cannot
compile with VS
• Here a list of possible clients:
– Visual Studio (if you are using the BizTalk explorer)
– BizTalk Administration
– BizTalk service
90
Misc
• If you change some of the configuration settings on the
registry file you need to:
– Remove the adapter from the BizTalk adapter list
– Re-register the new reg file
– Add the adapter the BizTalk adapter list
91
Test cases
• Tested
– Management interfaces (Visual Studio, BTS Admin)
– One-Way receive static port
– Request-response static port
– One-Way send static port
– Solicit-Response static port
– Dynamic Send Ports
– Exception handling (& message suspension)
92