Export (0) Print
Expand All
1 out of 2 rated this helpful - Rate this topic

BizTalk Server 2006: BizTalk WS-Addressing Helper

Angus Foreman (Principal Consultant, Microsoft UK)

October, 2006

Summary: This document defines the WS-Addressing Helper, explains its function, and describes how to utilize it. Installation instructions for the WS-A Helper are also provided. Sample coding is shown in the Appendices.

Consider the following scenario: A Microsoft® BizTalk® Server application needs to connect to a Web Services Enhancements for Microsoft .NET (WSE) 2.0 Web service that is hosted on a server located behind a proxy (or firewall). The BizTalk Server application communicates via HTTPS to a port on the proxy server. The proxy server converts the HTTPS to HTTP and forwards messages to the destination WSE Web service as shown in the following diagram.

Aa972203.e005ecc7-37eb-441f-b926-47e17bd6a8ac(en-US,BTS.10).gif

Issue:

When using BizTalk Server, the BizTalk Adapter for WSE does support communication through a proxy server, however the WSE 2.0 Web service may reject the incoming SOAP message if the Web service is using Web Services Enhancement SOAP extensions (WSE). (Note that the message will not be rejected if the Web Services Enhancement SOAP extensions are not activated.)

In more detail:

The Web service rejects the request if either of the following is true:

  • The <wsa:To> element does not match the URL that the Web service is being run on.
  • The <wsa:To> element does not match the SOAPActorAttribute value that has been specified on the Web service.

The reason the message will be rejected in the scenario described above is that the BizTalk Adapter for WSE forces the <wsa:To> value to be the same value as the destination URL in the WSE send adapter. This means that in the case where the WSE send adapter is sending to a proxy server with the location of "http://proxyserver.myorg.com" then the <wsa:To> value will also be "http://proxyserver.myorg.com". This value is unlikely to match either the URL of the Web service or the SOAPActorAttribute, and hence the message will be rejected by the Web service. This rejection will be denoted to the client with a message similar to the following:

Failed to transmit message. Exception : System.Web.Services.Protocols.SoapException: Destination Unreachable --> WSE817. The <To> header must match the Actor attribute on this receiver. The <To> header contained "some URI/URL here" whereas the Actor attribute was "different URI/URL".

Workaround:

The BizTalk WS-Addressing Helper is designed to work alongside the BizTalk Server 2004/2006 WSE send adapter. It is designed to enable developers to control the value of the <wsa:To> element in outbound WSE messages. Once installed the helper requires a small amount of design-time configuration, which can easily be carried out within an orchestration or pipeline.

Technologies involved in the scenario:

  • BizTalk Server 2004 / 2006
  • BizTalk Server WSE Adapter (Send)
  • Web Services Enhancements 2.0

The BizTalk WS-Addressing helper ("WS-A Helper" for short) is designed to enable the following scenario:

  • BizTalk Server 2004/2006 is sending outbound SOAP messages that include WS-A headers.
  • The outbound SOAP message sent by the WSE send adapter needs to contain a specific <wsa:To> address that is not the same as the physical endpoint configured in the WSE send adapter.

The WS-A Helper is implemented as a WSE custom output filter. This implementation gives it the ability to modify the outbound SOAP message as it is sent by the BizTalk Server WSE send adapter. The WS-A Helper uses this capability to update the WS-Addressing <wsa:To> element to reflect a value specified by the developer.

The developer specifies the value for the <wsa:To> element by using the WSE adapter’s capability to allow custom SOAP headers to be constructed within an orchestration or pipeline. The developer implements a solution that creates a specific custom SOAP header that contains the value that is to be used by the <wsa:To> element.

When a message is sent via the WSE Adapter the following occurs:

  • The WS-A Helper intercepts the outbound message.
  • The WS-A Helper reads the value of the custom SOAP header.
  • The WS-A Helper replaces the <wsa:To> value with the value from the custom SOAP header.
  • The WS-A Helper removes the custom SOAP header.
  • The WS-A helper passes back the message for onward delivery.

The following steps install the adapter and need only be carried out once on every BizTalk server that is running the WSE send adapter.

  1. The WS-A Helper comprises a single class. Code for the class is in Appendix 3. Save this code into a file named WSAddressingOutputFilter.cs and compile it into an assembly. You can use the following command for compilation that will create the BizTalk.WSEFilter.dll assembly. Alternatively, you can create a Microsoft Visual Studio® project and add this file to it.
    Csc /t:library /out:BizTalk.WseFilter.dll WSAddressingOutputFilter.cs /reference:” \Program Files\Microsoft WSE\v2.0\Microsoft.Web.Services2.dll”
    
  2. Copy the WS-A Helper assembly file into the BizTalk Server installation directory.
  3. Make a backup copy of the BTSNTSVC.config file (also located in the BizTalk Server installation directory).
  4. Update BTSNTSVC.config as in the following steps.
  5. If the section starting <section name="microsoft.web.services2" does not exist in BTSNTSVC.config then add this section exactly as it appears below. Note that if the <configSections> tags do not exist they will need to be added.
      <configSections>
        <section name="microsoft.web.services2" type="Microsoft.Web.Services2.Configuration.WebServicesConfiguration, Microsoft.Web.Services2, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
      </configSections>
    
  6. If the section starting <microsoft.web.services2> does not exist in BTSNTSVC.config then add this section exactly as shown below.
    <microsoft.web.services2>
    </microsoft.web.services2>
    
  7. Within the <microsoft.web.services2> section the filters are specified by adding the following section exactly as it appears. Note if other output filters are already in place, re-use the same section of .config file (do not create a new one).
        <filters>
            <output>
                <add type=" BizTalk.Samples.WSA.WSAddressingOutputFilter, BizTalk.WseFilter"/>
            </output>
        </filters>
    
  8. Compare the resulting file against the example BTSNTSVC.config file in Appendix 1.

Specifying the Desired <wsa:To> Value

The desired <wsa:To> value is specified by the developer at design time within an orchestration or pipeline. The WS-A Helper reads the value from a custom SOAP header with the specific element name of <CustomSOAPActor>. To specify the <wsa:To> value, the developer must create a custom SOAP header on the outbound SOAP message with the <CustomSOAPActor> element name and place the desired <wsa:To> value within its bounding tags. The following example shows a <wsa:To> value of http://localhost/BatchWebService/BatchWebService.asmx being specified.

<CustomSOAPActor>http://localhost/BatchWebService/BatchWebService.asmx</CustomSOAPActor>

Custom SOAP headers can be simply created within an orchestration, or alternatively may be created within a pipeline (if a Content Based Routing solution has been developed).

To create the necessary custom SOAP headers within a BizTalk orchestration use the code shown below within a message assignment shape. The following table shows the custom header being set to a value of "http://localhost/BatchWebService/BatchWebService.asmx" for a message called "WSReq".

WSReq(WSE.SoapHeaders)="<CustomSOAPActor>http://localhost/BatchWebService/BatchWebService.asmx</CustomSOAPActor>";

Note   The solution must have a reference to C:\Program Files\Microsoft BizTalk Server Adapter for WSE 2.0\Microsoft.BizTalk.Adapter.WSE.Properties.dll to enable access to the WSE properties.

Note   The WSE.SoapHeaders must be set within a message assignment shape due to the constraint on all messages being immutable (un-modifiable) once created.

Within a BizTalk orchestration, this assignment of the custom SOAP header will be placed within a message assignment shape as shown in the following diagram. Note that the whole of the assignment statement is not visible in this diagram.

Aa972203.9f61fcdb-e78e-48e4-8981-e2fda6cf8a4e(en-US,BTS.10).gif

Assuming that the WS-A Helper has been installed, the preceding steps are all that is required to set the <wsa:To> element to a user-defined value.

For further notes on debugging when using the WS-A Helper see Appendix 2.

Example BTSNTSVC.config File

The following is an example BTSNTSVC.config file:

<?xml version="1.0"?>

<configuration>

<configSections>

<section name="microsoft.web.services2" type="Microsoft.Web.Services2.Configuration.WebServicesConfiguration, Microsoft.Web.Services2, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

</configSections>

<runtime>

<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

<probing privatePath="BizTalk Assemblies;Developer Tools;Tracking;Tracking\interop" />

</assemblyBinding>

</runtime>

<system.runtime.remoting>

<channelSinkProviders>

<serverProviders>

<provider id="sspi" type="Microsoft.BizTalk.XLANGs.BTXEngine.SecurityServerChannelSinkProvider,Microsoft.XLANGs.BizTalk.Engine" securityPackage="ntlm" authenticationLevel="packetPrivacy" />

</serverProviders>

</channelSinkProviders>

<application>

<channels>

<channel ref="tcp" port="0" name="">

<serverProviders>

<provider ref="sspi" />

<formatter ref="binary" typeFilterLevel="Full" />

</serverProviders>

</channel>

</channels>

</application>

</system.runtime.remoting>

<appSettings>

<add key="ErrorLogManager_ConnectionString" value="Integrated Security=SSPI;Initial Catalog=frameworkservices;Data Source=W2003VPC-A" />

<add key="AuditConnectionString" value="Integrated Security=SSPI;Initial Catalog=frameworkservices;Data Source=W2003VPC-A" />

<add key="NaspLookupConnectionString" value="Integrated Security=SSPI;Initial Catalog=frameworkservices;Data Source=W2003VPC-A" />

</appSettings>

<microsoft.web.services2>

<security>

<x509 storeLocation="CurrentUser" />

</security>

<diagnostics>

<trace enabled="true" input="InputTrace.webinfo" output="c:\tmp\OutputTrace.webinfo" />

<policyTrace enabled="true" input="ReceivePolicy.webinfo" output="c:\tmp\SendPolicy.webinfo" />

</diagnostics>

<filters>

<output>

<add type=" BizTalk.Samples.WSA.WSAddressingOutputFilter, BizTalk.WseFilter "/>

</output>

</filters>

<policy>

<cache name="C:\Program Files\Microsoft BizTalk Server Adapter for WSE 2.0\Policy\PolicyCache.xml" />

</policy>

</microsoft.web.services2>

</configuration>

  • The following code sections, included in the example above, may already exist within the file if the WSE adapter has been previously utilized. If any of these do not exist they will need to be added as shown:

<section name="microsoft.web.services2" type="Microsoft.Web.Services2.Configuration.WebServicesConfiguration, Microsoft.Web.Services2, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

<microsoft.web.services2>

<filters>

<output>

</output>

</filters>

</microsoft.web.services2>

  • The following code, which was included in the example above, will not exist and will need to be added:

<add type=" BizTalk.Samples.WSA.WSAddressingOutputFilter, BizTalk.WseFilter "/>

  • The following code from the example above shows the optional tracing configuration that is discussed in Appendix 2:

<diagnostics>

<trace enabled="true" input="InputTrace.webinfo" output="c:\tmp\OutputTrace.webinfo" />

<policyTrace enabled="true" input="ReceivePolicy.webinfo" output="c:\tmp\SendPolicy.webinfo" />

</diagnostics>

Debugging When Using the WS-A Helper

Debugging the execution of the WS-A Helper

The WS-A Helper contains some lightweight tracing that may be useful when diagnosing unexpected behaviour. The tracing is visible using "Debug View" (www.sysinternals.com) or similar tools.

All tracing output from the WS-A Helper is prefixed by "WSAddressingOutputFilter:"

The tracing indicates the following events:

Trace-output Explanation

WSAddressingOutputFilter; In ProcessMessage()

The filter has started processing an outbound message

WSAddressingOutputFilter; InputSOAPenv:

Displays the SOAP message prior to the helper processing the message

WSAddressingOutputFilter; Failed to locate temporary node:

Indicates that the helper could not locate the <CustomSOAPActor> element

WSAddressingOutputFilter; Failed to locate the wsa:To element

Indicates that the helper could not locate the <wsa:To> element

WSAddressingOutputFilter; OutputSOAPenv:

Displays the SOAP message after to the helper has processed the message

WSAddressingOutputFilter; Unexpected exception ocurred:

Displays an unhandled exception

Tracing the outbound WSE SOAP traffic

WSE natively supports the ability to log incoming and outbound messages. This can be configured using a diagnostics section of the .config file that controls the application performing the WSE operations. In the case of BizTalk Server this is the BTSNTSVC.config file. The tracing elements of the WSE configuration are shown in magenta in the example BTSNTSVC.config file included in Appendix 1

Sample code for the WS-A Helper

using System;

using System.Xml;

using Microsoft.Web.Services2;

namespace BizTalk.Samples.WSA

{

public class WSAddressingOutputFilter : SoapOutputFilter

{

const string TempSOAPActorNodeName= "CustomSOAPActor";

const string wsaToNodeName= "To";

public override void ProcessMessage(SoapEnvelope envelope)

{

System.Diagnostics.Trace.WriteLine("WSAddressingOutputFilter: In ProcessMessage()");

System.Diagnostics.Trace.WriteLine("WSAddressingOutputFilter: InputSOAPenv: " + envelope.InnerXml);

try

{

// Look for specific temp SOAPHeader holding the wsa:To value we want to set

XmlNamespaceManager Tempnsmgr = new XmlNamespaceManager(envelope.NameTable);

Tempnsmgr.AddNamespace("gm", "http://tempuri.org/ws-addressing");

string LocateTempNodeXPath = "*[local-name() = '" + TempSOAPActorNodeName + "']";

XmlNode TempActorNode = envelope.CreateHeader().SelectSingleNode( LocateTempNodeXPath,Tempnsmgr);

if ( TempActorNode == null )

{

// because this filter always runs regardless of message types it is valid for the

// node we are searching to not be present

System.Diagnostics.Trace.WriteLine("WSAddressingOutputFilter: Failed to locate temporary node:" + TempSOAPActorNodeName);

return;

}

// Look for wsa:To value so we can set its value

XmlNamespaceManager WSnsmgr = new XmlNamespaceManager(envelope.NameTable);

WSnsmgr.AddNamespace("wsa", "http://schemas.xmlsoap.org/ws/2004/03/addressing");

string LocatewsaToNodeXPath = "*[local-name() = '"+wsaToNodeName+"']";

XmlNode wsaToNode = envelope.CreateHeader().SelectSingleNode(LocatewsaToNodeXPath,WSnsmgr);

//--XmlNode wsaToNodeModified = wsaToNode.CloneNode(false);

if ( wsaToNode == null )

{

// we would expect to find a wsa:To node if we have already found the TempSOAPActorNode node

// so we treat the lack of a wsa:To as significant enough to log but not to cause exception

System.Diagnostics.Trace.WriteLine("WSAddressingOutputFilter: Failed to locate wsa:To element using the XPATH: "+ LocatewsaToNodeXPath);

return;

}

System.Diagnostics.Trace.WriteLine("WSAddressingOutputFilter: Temp & To elements sucessfully located");

// replace the old wsa:To node with the Temp value

wsaToNode.InnerXml=TempActorNode.InnerXml;

// remove the temp actor node from the header

envelope.Header.RemoveChild(TempActorNode);

System.Diagnostics.Trace.WriteLine("WSAddressingOutputFilter: OutputSOAPenv: " + envelope.InnerXml);

}

catch (Exception exc)

{

System.Diagnostics.Trace.WriteLine("WSAddressingOutputFilter: Unexpected exception ocurred: " + exc.Message);

}

}

}

}

Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft. All rights reserved.