I started the first post on this, with "this is interesting, sort of" - well judging by the number of people who've asked me for more details on doing it I think I was wrong. Apologies to all, I've been so busy the last few months that I just haven't had time to get some code examples up there...until now!
Get the code here to try this for yourself. Essentially, this is an example of what I discussed before, where you can do dynamic sends using the SOAP adapter. For those that haven't tried it, you might be thinking, what's the big deal, but as I mentioned, theres a couple of gotchas which stop this from working as cleanly as with other adapters.
The first is that you can't just set the OutboundTransportLocation from an orchestration (or receive pipeline) as you would do for other dynamic adapters. This is because the Uri scheme (the bit before the address, e.g. HTTP://) is used by BizTalk to lookup the adapter alias from the adm_AdapterAlias table in the management database. As the SOAP adapter only supports SOAP over HTTP you must set the scheme to SOAP:// in order to route it correctly. But this won't work because then the ASMX proxy plumbing (called by the adapter) will fail as it is expecting HTTP:// and will make the call using SOAP:// instead. The way round this is to set the Microsoft.XLANGs.BaseTypes.Address property of the port - which will deliver the message to the SOAP adapter - and then set the OutboundTransportLocation context property in the Send pipeline. The example code shows how to call a Web service using this technique by pulling the Uri to send the message to from the inbound message itself. This dynamic routing is extremely powerful and very useful for Web services.
The second gotcha is around the use of a proxy. When you add a Web reference to a BizTalk project, similar (but not identical) logic is used to classic ASMX whereby a proxy is generated from the URL you provide in the wizard. The proxy contains the Web methods that map to the operations on the provider's WSDL. The problem is that you end up baking the service interface into the client. Rather than creating a client proxy for each client (which is a pain), what we really want is a generic proxy capable of calling any client. Worse than this, ASMX forces the SOAPAction HTTP header (for SOAP 1.1 support) to match the name of this method which makes it very inflexible. Changing this however turns out to be pretty easy using reflection. The code in the download overrides the Invoke method of the SoapHttpClientProtocol in the System.Web.Services.Protocols namespace. Normally this method is called by the Webmethod passing the name of the Webmethod itself (which is Dispatch in the sample). Invoke itself then uses reflection to get the method parameters etc to formulate the call to the service implementation. To keep things simple the code here only deals with a single parameter, XmlNode. Of course you could easily extend this if you wanted to but then you'd be wanting to pass multiple Xml docs which kinda goes against the philosophy of doc/lit. The orch's Send port is then configured to use our generic proxy and call the Dispatch method to make this all work.
There are three projects in the solution, BizTalk (with the Send pipeline and Orch), the generic proxy called by the SOAP send adapter and a simple Web service implementation to call. Simply compile everything, deploy the BizTalk project and GAC the generic proxy assembly. Deploying will create all the ports (sorry about the names) - just create a folder c:\webrefsfilein and enlist and start the orch. You can then drop in the xml file in the Test Data folder in the BizTalk project. There is tracing code throughout, so grab the invaluable sysinternals (sorry, Microsoft) tool, Debug Viewer here. Run the solution (with the Web service as the default startup). When you drop the file in it should call the Web service (specified in the file) and return a result, logging the call (see pic below). Enjoy!
Posted
Jun 07 2007, 02:00 PM
by
jon-fancey