This fifth article in a series on BizTalk Server 2006 R2 and Windows Communication Foundation (WCF) integration, the focus shifts to exposing WCF services endpoints out of BizTalk Server. This article addresses the various mechanisms for creating WCF operations out of BizTalk Server for consumption by a client. The next article(s) will cover security, transactions and attachments.
Scenario #1 – Exposing One-Way Service (HTTP) For Content Based Routing
In this scenario, a message is received from a WCF service and processed by only the Messaging Engine, not an orchestration.
First off, an XSD schema reflecting a “BulkOrder” of a product was created in a new Visual Studio.NET BizTalk Server project.
At this point, this is the only BizTalk project artifact needed. Unlike using the basic SOAP BizTalk Web Services Publishing Wizard, one does NOT have to deploy their BizTalk solution prior to using the BizTalk WCF Service Publishing Wizard. The BizTalk Web Services Publishing Wizard always uses the version of the project assembly in the GAC, meaning a project had to be deployed (and GAC-ed) to see all the relevant artifacts. The BizTalk WCF Publishing Wizard only requires a project to be built (i.e. a dll compiled).
When the BizTalk WCF Publishing Wizard is started up, the following screen is presented.
There are two clear options available: create a new service endpoint (using either the WCF-WSHttp, WCF-BasicHttp, or WCF-CustomIsolated adapters), or create a metadata-only endpoint. For this first scenario, the former was chosen. The “Enable metadata endpoint” causes the “httpGetEnabled” flag to be set to true, thus enabling someone to retrieve the WSDL. This wizard page also allows the user to chose to automatically create a WCF receive location with all the relevant settings preconfigured.
Next, the user is asked whether they wish to “Publish orchestrations as WCF service” or “Publish schemas as WCF service.” This is the same option presented to users of the classic BizTalk Web Services Publishing Wizard. For this particular scenario, the “Publish schemas” option was chosen. From this next wizard page, the user can manually create the service, operation and message they wish. For this scenario, the snapshot below shows a one way service operation named “PublishBulkOrder.”
After choosing a target namespace for the service, the user is asked where to deploy the service.
Notice that a “Browse” button is finally available in BizTalk Server 2006 R2 for choosing the host. After a confirmation step, the wizard generates the WCF service and deploys it to the chosen IIS web site container.
If one browsed this service immediately after deployment (and turned off custom errors in the web.config file), they may see the following result in their web browser:
The BizTalk documentation mentions that if you have Windows SharePoint Services involved, you may have to add to the element. Once that is added, the browser reports a different error with the service.
The receive location for this service needs to be online for this service to function properly because each receive location acts as a generic ServiceHost for WCF. If the auto-generated receive location is enabled (and ServiceHost thus opened), then the browser would show a page similar to this:
The “OneWayOperationService.svc” has only the simple ServiceHost declaration at the top. The ServiceHost element has the “Factory” attribute which points to the Microsoft.BizTalk.Adapter.Wcf.Runtime.WSHttpWebServiceHostFactory object. Using Reflector, one can see that BizTalk overrides the WCF ServiceHostFactory object in order to dynamically return a generic service host based on the receive location.
Using the mapping between the service URI and the receive location address, the appropriate receive location is loaded and used as the service host.
The web.config file associated with this auto-generated service has a few interesting components as well. First off, there is a custom configuration section, , which contains flags for launching the debugger when hosts are created, as well as other settings which would be turned on during development or testing only.
Within the node, one can see that this service is named Microsoft.BizTalk.Adapter.Wcf.Runtime.BizTalkServiceInstance. This value does NOT correspond to the receive location name and is the same for any BizTalk-generated WCF service. Note that the receive location name is NOWHERE in this configuration file. That value is looked up when the service is called, instead of hard-coding it in this configuration.
The next step was to generate the proxy class and application configuration file used by the client to cal the WCF service. The svcutil.exe utility was run against the IIS service’s WSDL created above. The following code block was used in a WinForm client to call the WCF service.
Notice that the svcutil-generated proxy class is used instead of using the WCF channel factory. Unless there are runtime-decided binding, endpoint or contract considerations, the proxy class mechanism is the simplest way to consume the WCF service. However, it does require that the application configuration be fully flushed out at design time.
Before executing this scenario, the Visual Studio.NET BizTalk project needs to finally be deployed (note that above, the wizard could be executed without the project being deployed yet). After deployment, a valid send port is needed to accept the message published via the WCF service.
If the send port was stopped and the BizTalk-generated WCF service was called, then the message context can be inspected. Specifically, there were WCF adapter-specific context properties that were visible.
There are context fields such as Action (which holds the SOAPAction), ReplyTo, To (destination endpoint), and more. The full list of WCF adapter property schema values can be found in the BizTalk Server 2006 R2 documentation.
Before moving to the next scenario, let’s briefly review the exception management capability of the BizTalk Server receive location. Let’s examine four possible exception situations.
- Exception Situation #1 – Receive location offline.
What does the WCF service consumer see if the receive location is offline? As might be expected, the consumer gets a ServiceActivationException which says:
The requested service, ‘http://ws03vssql05/Seroter.BizTalkWCFTutorials.ExposeOperations.OneWayOperation/OneWayOperationService.svc’ could not be activated
The receive location must be enabled for the service to be called.
- Exception Situation #2 – No subscribers, default receive location settings
If a message comes in from the WCF adapter (one-way), and no subscribers are found, under the default receive location settings, the consumer would get an error saying:
The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.
In this scenario, the client gets no details about what went wrong.
- Exception Situation #3 – No subscribers, receive location returns exception
The “Messages” tab of the receive location adapter configuration provides two “Error Handling” options.
If the “Include exception details in fault” checkbox is selected, and a WCF message is submitted where no subscribers exist, the caller gets the following error:
The published message could not be routed because no subscribers were found. This error occurs if the subscribing orchestration or send port has not been enlisted, or if some of the message properties necessary for subscription evaluation have not been promoted.
The caller gets the same error that BizTalk would have stored. Also note that there is no suspended message within BizTalk that can be resumed (an Error Routing Report may be found, but no instance of the actual bad message is stored within BizTalk). This is a useful setting during development, but probably not ideal in a production application. For security reasons alone, the internal failings of the message bus shouldn’t be revealed to service callers.
- Exception Situation #4 – No subscribers, message suspended in BizTalk
The easiest way to allow the caller to succeed, while still recording an error, is to suspend failed messages in BizTalk, which suppresses the exception message back to the WCF client.
Notice in the picture above that the “Suspend request message on failure” checkbox is selected. In this case, if an exception occurs on receipt, the caller receives an HTTP “ok” message, while BizTalk suspends the message with the full error.
In this case, the full error details are captured (along with the failed message itself), while the details of the failure are hidden from the WCF service caller.
Scenario #2 – Exposing Two-Way Service (HTTP In-Process) For Orchestration
Now that one-way services have been looked at, let’s explore how two-way services are generated from BizTalk. Instead of hosting this WCF service in IIS, this example shows how to host the HTTP-based WCF service endpoint directly within BizTalk itself.
This demonstration uses a simple orchestration and a request-response input port. The outbound message is of the same type as the inbound, and the “status” value is changed to “received” before returning the response.
Note that just like with exposing schemas as web services, the new BizTalk WCF Service Publishing Wizard allows the user to publish orchestrations as web services WITHOUT deploying the Visual Studio project. Because this scenario involves an in-process HTTP service, the wizard will only be used to generate a metadata endpoint. So, before running the wizard, the receive location hosting the in-process HTTP WCF endpoint was created.
It is not necessarily obvious how to use the HTTP binding for an in-process adapter. In viewing a receive location’s properties, it’s impossible to select the WCF-WSHttp adapter and also choose a non-isolated host. However, the WCF-Custom CAN be chosen alongside the available in-process host(s).
The first thing entered when configuring this custom endpoint is the address.
Next, it is critical to add the desired binding. In this demonstration, that’s WS-Http.
How to expose metadata for an in-process HTTP endpoint? When the BizTalk WCF Service Publishing Wizard was executed, and a MEX endpoint created for this receive location, the following error occurred when browsing the new MEX service in IIS:
This collection already contains an address with scheme http. There can be at most one address per scheme in this collection.
This error doesn’t have to do with mixing MEX endpoints and “regular” endpoints in the same IIS web site, but rather, creating MEX endpoints for in-process HTTP bindings seems to trigger this. Note that an IIS-hosted MEX endpoint CAN be created for IIS-hosted HTTP endpoints, but not for in-process hosted HTTP endpoints.
Back to the original question, then, of how to properly call an in-process HTTP endpoint? There seem to be two options. The first option would be to add a metadata behavior to the receive location and use the WCF svcutil.exe application to generate a (generic) proxy and contract. Because a receive location isn’t “typed” to a particular contract, there is no application-specific information revealed by exposing metadata on a receive location itself. The user would have to do the additional step of generating an object representation of the XSD schema (using a tool like xsd.exe). The proxy class (and contract) generated by svcutil.exe for the WCF-Custom receive location (ITwoWaySync) has a single operation named BizTalkSubmit. One could create a WCF Message object using the xsd.exe-generated type class using the line of code below:
However, calling the “BizTalkSubmit” function on the TwoWayAsyncClient object results in a “System.NotSupportedException: Specified method is not supported” error. That makes sense given what the documentation says about using this interface. So, trying to deal with this untyped, generic interface with no additional resources would require some funky activities.
The second option may be simpler. First, during development, a stub WCF service was generated using the BizTalk WCF Service Publishing Wizard and temporarily hosted in IIS. During the wizard walkthrough, metadata was enabled, and a receive location was NOT created, as all that’s desired was the service (metadata) itself.
Then the WCF svcutil.exe tool was used to generate the proxy class and configuration settings needed for the service. Next, the endpoint address in the configuration file was modified (to point to the BizTalk-hosted HTTP service) and the proxy class utilized to call the BizTalk-hosted service. This scheme works great, the only downside being that several temporary assets need to be created in order to regenerate the proxy class during future releases.
Scenario #3 – Exposing Two-Way Simple Type Service (TCP) For Orchestration
The “classic” SOAP adapter allowed simple data type parameters to be transmitted to and from BizTalk. This demonstration takes an orchestration with simple type parameters and exposes it as a WCF service using the TCP binding.
The orchestration has an input message, “ProductId” of .NET type System.Int32. The orchestration returns a message named “StockStatus” which is of type System.String.
After building and deploying this project, a TCP request/response receive location was created. Then, after the BizTalk Web Services Publishing Wizard was run (for comparison purposes), the BizTalk WCF Service Publishing Wizard was executed. A metadata endpoint was needed for the in-process BizTalk TCP receive location. Once the metadata service was created in IIS, service artifacts were generated using svcutil.exe and added to the WCF client application.
Calling the SOAP wizard generated service resulted in a calling statement that looked like this:
Notice that an integer named “part” is accepted, and a string is returned.
When the WCF operation was called, the statement looked like this:
Here there is a parameter named “@int”, and a string is returned. When the WCF version of the service is called, a string is returned, as expected. This may not be a desirable solution as the caller is forced to know what exactly the unnamed parameter value should hold. Note that the SOAP adapter service CAN have distinct parameter names by using multi-part messages.
Scenario #4 – Exposing Two-Way Multi-part Service (HTTP) For Orchestration
How about the situation where the BizTalk designer wants multiple parameters to appear in their exposed service? This demonstration uses an orchestration which accepts, and returns, a multi-part message type using an IIS-hosted WCF endpoint.
Notice that “BulkOrderType” has two parts: “BulkOrder” which maps to a schema, and “CustomerId” which is a System.String. As with the scenario above, both a “classic” SOAP service and WCF service were generated for this orchestration.
The “classic” SOAP service was called using the following command:
Notice that the (named) parts of the multi-part message show up as individual parameters of the method signature. For the WCF service, ONLY the “body” part shows up as a operation parameter …
This is because the WCF adapters don’t support multi-part messages. Depending on the solution, this may be a reason to go with the “classic” SOAP adapter vs. the WCF adapter. When calling the WCF version of this service, an “MissingPartException” error is generated by the orchestration engine:
The XLANG/s message has no part at index ‘1’. The total number of parts found in the message is ‘1’.
Scenario #4 – Exposing Two-Way Service (HTTP) For Orchestration With Fault
Finally, let’s look at how faults are returned from orchestration exposed as WCF services. The BizTalk Server 2006 R2 documentation clearly states that typed fault contracts cannot be returned from orchestrations exposed as WCF services. While orchestrations can CONSUME typed fault messages, they cannot expose them.
So, WCF faults are returned much like SOAP faults from orchestrations. The below orchestration receives a message, sends a response, but if an exception is raised within the orchestration, a fault message is returned instead. The orchestration does a “divide by 0” in the response message construct block, thus causing an exception to occur at runtime.
By wrapping the “send” shape in a long-running transaction scope, the orchestration decision in the exception block can check “succeeded(Transaction_SendResponse)” (meaning the transaction wrapping the send completed successfully) and create a fault response message if necessary.
After building another IIS-hosted WCF service (and auto-generating the receive location), and adding the service metadata to the WCF client, the service was called and returned the following error:
The server was unable to process the request due to an internal error.
If “Include exception details in faults” was then checked in the receive location’s configuration, a subsequent call to the service returned the following error:
error: System.DivideByZeroException: Attempted to divide by zero.
Just like with scenario #1, exceptions can be as opaque or chatty as the developer chooses. In production systems, it most often safest to err on the side of opaqueness.
This article has shown a variety of ways to create WCF services and MEX endpoints from BizTalk artifacts. It is fairly simple to generate either schema-based or orchestration based services for IIS hosting and MEX endpoints for BizTalk-hosted endpoints. We also saw the various flags in receive location for returning exceptions to the WCF callers. We discovered that while the WS-Http binding can be hosted in-process, it is not particularly easy to get the metadata needed to call the service. Finally, we saw some considerations when using simple type parameters, multi-part messages and fault messages.
As far as recommendations, in nearly all cases I recommend using the “expose schemas” option of the service generation wizards, whether you’re building content-based routing or orchestration scenarios. The control over the WSDL generation (service name, operations) far outweighs the convenience of the orchestration-based service generation. The only reason I use the “service from orchestration” choice in the Web Services wizard was to make use of multi-part messages or XML “any” input types. Now that multi-part messages are not supported by the WCF adapters, I have virtually no reason to use the orchestration-generated service option.
Once this entire BizTalk+WCF series is complete, I will make the entire source code available.
Questions, comments or corrections? Go ahead and leave a comment on my blog post about this article.
You can read more about BizTalk, SOA and enterprise architecture on my blog at https://seroter.wordpress.com.