Wednesday, April 23, 2008

Review: John Stockton Silverlight 2.0 Presentation

Last night I got to the Cleveland C#/VB.NET SIG to hear John Stockton talk about Silverlight 2.0 Beta 1. Although this beta has only been out a few weeks, John has already written a couple of apps in it, which he demonstrated. The first demo was based on a POC John had written for an actual client in about 10 days. It took an XML file containing a description of a telephone switching system, and it drew a two-dimensional picture of the system. Drawing the picture seemed straitforward enough (they're just boxes stacked in racks), but each box was animated to display its specs when touched with the mouse. The second demo was an early iteration of the web page that will display events at Cleveland Day of .NET. I was a bit disturbed by that one because it said John and I would be the only presenters. (Fear not, that will change!)

Though he freely admits that he's still learning, John's experience playing with Silverlight 2.0 beta 1 from its day of release has made him already one of the world's top experts. I admired his willingness to get right to work with it, and he made it seem approachable to the rest of us.

I still have a lot of questions about how ready Silverlight is for prime time. (How's the security? How's it deal with latency, concurrency, message brokering? Is the cross-platform cross-browser story real? How far can you really get away from Javascript?) And of course a lot of that approachability we perceived is because it's .NET and we're .NET developers. But the fastest way to the answers is to try the stuff out, as John has done.

After the meeting a gang of 16 or so escaped to Winking Lizard, which appears to be a strong tradition with this SIG, although we're doing much more of it now in that other Cleveland .NET SIG that I chair. I enjoyed meeting new .NET developers as well as catching up with Sam and some Twitterati.

Overall a very enjoyable and informative geek night out.

Saturday, April 12, 2008

Fixing BizTalk's WCF Message Contract Mix-Up, Part 3

The final solution to the Message Contract Mix-Up doesn’t require you to define your own message contracts, but does require some tricks in both the operation contract and the BizTalk ports.

First, modify the operation contract by adding a MessageParameterAttribute to the argument and return type:

[OperationContract]
[return:MessageParameter(Name="OrderStatus")] PurchaseOrderStatus PlaceOrder([MessageParameter(Name="PurchaseOrder")]PurchaseOrder po);

MessageParameterAttribute lets you change the names that the parameter and return value will have in the SOAP body. The names need to be changed to “PurchaseOrder” and “OrderStatus” so BizTalk can associate the schemas PurchaseOrder.xsd and OrderStatus.xsd with those elements. (Without MessageParameterAttribute, WCF would force the names of the parameter and return value to be “po” and “PlaceOrderResult”, which mean nothing to BizTalk).

Now you need to modify the WCF adapter settings in the two-way receive location in BizTalk. For general instructions and screenshots illustrating the following steps see the BizTalk documentation here. Open the Messages tab of the WCF adapter. Under “Specify the source of the inboud BizTalk message body”, check the third radio button, “Path – content located by body path”. In the text box type an XPATH expression consisting of the name of your operation contract, followed by the name of your data contract schema:

/*[local-name()='PlaceOrder']/*[local-name()='PurchaseOrder']

Make sure the combo box below the text box, “Node encoding”, is set to XML.

The first element in the XPATH is actually the WCF-generated message contract, which has the same name as the operation contract (“PlaceOrder”). The following element is the name of the parameter inside the message contract, which we forced to be “PurchaseOrder” by applying the MessageParameterAttribute.

The consequence of these settings is that the WCF adapter will drill through the message contract and pass the PurchaseOrder element to BizTalk as the message body. Bingo!

Since this is a two-way port, we need to return a data contract back to the caller, and to do that we need to tell the WCF adapter how to wrap the data contract inside a message contract. To do that, go to the bottom half of the tab and check “Template – content specified by template.” In the text box below, be careful not to delete or change the bts-msg-body element that’s already there, since that represents the data contract part of the message. Instead, insert an XML element around the bts-msg-body to represent the message contract. The name of this element is the operation contract’s name plus the suffix “Response”, and it must include the correct XML namespace:

<PlaceOrderResponse xmlns="urn://MyCompany.Purchasing.1_0_0.com" >
<bts-msg-body xmlns="http://www.microsoft.com/schemas/bts2007" encoding="xml" >
</PlaceOrderResponse >

If this were a one-way send port we would follow the same procedure.

The result is that BizTalk will send the return value to client wrapped inside the same message contract that WCF would have generated automatically if the service were hosted in a pure .NET application. Bingo Bingo!

So there you have three ways to solve the Message Contract Mix-Up with the BizTalk WCF adapters. If you’ve read all the way through this series, I surmise that you either find the subject fascinating, or you need to solve these problems as badly as I did.

Fixing BizTalk's WCF Message Contract Mix-Up, Part 2

I know of three ways to fix the Message Contract Mix-Up discussed in the last post. The first two require changing the signatures of your operation contracts to replace the WCF-generated message contracts with message contracts you define yourself. (Perhaps you've read books or heard WCF experts who say you needn't bother defining message contracts except in the unusual case. Then I guess BizTalk is an unusual case, as you might have suspected.)

1. Change the operation contract’s parameter and return value to message contracts with IsWrapped = false, like this:

[ServiceContract(Namespace = "urn://MyCompany.Purchasing.1_0_0.com")]
public interface IPurchasing
{
[OperationContract]
OrderStatusMessage PlaceOrder(PurchaseOrderMessage message);
}

[MessageContract(IsWrapped=false)]
public class PurchaseOrderMessage
{
[MessageBodyMember(Namespace = "urn://MyCompany.Purchasing.1_0_0.com")]
public PurchaseOrder PurchaseOrder;
}

[MessageContract(IsWrapped=false)]
public class OrderStatusMessage
{
[MessageBodyMember(Namespace = "urn://MyCompany.Purchasing.1_0_0.com")]
public OrderStatus OrderStatus;
}

If you declare your own message contracts but set IsWrapped to false (the default is true), then WCF will not generate any message contract element in the SOAP message at all. Instead, WCF will place the field with the MessageBodyMember attribute – which happens to be your data contract, PurchaseOrder – directly at the root of the SOAP body. Thus the SOAP message received by BizTalk will have an element named PurchaseOrder at its message type. Bingo! The great thing about this solution is you don’t need to do anything special on the BizTalk side to make your WCF adapters behave as you originally expected.

2. Same as 1. above, except the message contracts have IsWrapped = true. This will make the message contracts visible in your SOAP bodies, but you'll control their content instead of WCF. Generate XSD schemas for the message contracts and put them in your BizTalk project. Write message maps to transform message contract schemas to and from data contract schemas. Use the message maps to transform message contracts into data contracts in your inbound ports and to transform data contracts into message contracts in your outbound ports.

This solution will increase the number of schemas and message maps you’ll maintain. But unlike the previous solution, this one makes the message structures consistent, whether you look at them from the perspective of the WCF contracts, the BizTalk schemas, or the actual SOAP messages on the wire.

3. If you can’t, or aren’t willing, to define your own message contracts, but you’re able to add some WCF attributes, you can work out a compromise that allows BizTalk to navigate through the WCF-generated message contracts without knowing all about their schemas. The final post in this series will explain how to do that.

Fixing BizTalk's WCF Message Contract Mix-Up, Part 1

WCF developers often write OperationContracts that receive and return DataContracts, like so:

[ServiceContract(Namespace = "urn://MyCompany.Purchasing.1_0_0.com")]
public interface IPurchasing
{
[OperationContract]
OrderStatus PlaceOrder(PurchaseOrder po);
}

Suppose you implement this service in BizTalk using an orchestration. First you use a tool such as XSD.exe or SVCUtil.exe to generate XSD schemas for the PurchaseOrder and OrderStatus data contracts. You add these schemas to a BizTalk project, write an orchestration that receives a PurchaseOrder and returns an OrderStatus, and deploy the schemas and orchestration to BizTalk. Then you bind the orchestration’s receive-send port to a two-way receive location using a WCF adapter and the XmlReceive pipeline.

Your may be shocked to find that when a WCF client sends a message to BizTalk, an error occurs in the receive pipeline: “Finding the document specification by message type "urn://MyCompany.Purchasing.1_0_0.com #PlaceOrder" failed. Verify the schema deployed properly.”

It turns out that the SOAP body that your WCF client sent to BizTalk doesn’t begin with the PurchaseOrder data contract. Instead it begins with a message contract that the WCF client generated behind the scenes. The name of this message contract is “PlaceOrder”, i.e. the name of the operation. Inside that message contract is an element named “po” which contains the data exposed by the data contract. Thus although BizTalk expects to receive a message type named PurchaseOrder, there is no element named PurchaseOrder anywhere in the SOAP body!

There's a symmetrical problem at the other end, when the two-way receive port tries to return an OrderStatus to the caller. If the service were hosted in a .NET application, WCF would automatically generate a message contract element named PlaceOrderResponse and wrap it around the OrderStatus. But BizTalk by default will do no such thing.

I call this impedence mismatch the "BizTalk WCF Message Contract Mix-Up". But so much for lingo, how do you fix it? I can suggest three solutions, each with its pros and cons. I’ll discuss them in the next post.

BizTalk WCF Adapters: OneWay to Nowhere

Newcomers to the WCF Adapters in BizTalk Server 2006 R2 must be aware of two “gotchas” that they're likely to face when sending or receiving WCF messages with the adapters.

The first gotcha is that the IsOneWay property of operation contracts must be false. Luckily IsOneWay is false by default, but developers sometimes set it to true in an attempt to improve performance.

But the BizTalk WCF adapters always set IsOneWay to false, and so will fail whenever sending to or receiving from a client or service that has IsOneWay = true. (There’s an exception for the NetMsmq adapter.) Details about the errors you’ll receive are in the BizTalk documentation here.

The simple solution is to set IsOneWay back to false on your client or service. If you’re able to do that, the problem goes straight away.

If not – if for instance you lack authority to change the service contract – then you’ll have to put a wrapper service between BizTalk and the real service which, you guessed it, has the same WCF contracts as the real service except that IsOneWay is always false. This can be a pain, though it’s not hard to understand what you’re doing.

The second gotcha requires some deeper knowledge of WCF, so I’ll save it for the next post.

Friday, April 11, 2008

BizTalk Slides and Demos

The slides and demos from my Intelligent Programmer's Guide to BizTalk presentation are here.