Advanced BizTalk 2006 Web Services, Part II
In Part I of this two post series, I began a look at some advanced concepts around BizTalk-generated web services. In this post, we look at two additional concepts.
In the last post, I demonstrated the following topics ...
- Using the "bare" and "wrapped" settings during web service generation
- Creating multi-parameter web services via BizTalk
In this post, I'll investigate the final two points ...
- How the "one way" flag affects the web service
- Decoupling the BizTalk web service from a particular assembly
First of all, what does the Force Request Response flag in the Web Services Publishing Wizard actually do? The idea is that you can control whether you have a one-way or request-response service. It basically adds the OneWay flag to the generated class.
When I took a one way service (built using the Web Services Publishing Wizard) and then set the Force Request Response to "true", I expected that my one way service would actually return a response. My SOAP request/response looked like this ...
<soap:Body> <PostNewOrder xmlns="http://tempuri.org/"> <InsertOrder xmlns="http://Microsoft.Demo.Blog.AdvancedServices.InsertOrder_XML"> <OrderID xmlns="">string</OrderID> <CustomerName xmlns="">string</CustomerName> <ItemID xmlns="">string</ItemID> <Quantity xmlns="">string</Quantity> <Status xmlns="">string</Status> </InsertOrder> </PostNewOrder> </soap:Body>
and the *response* looked like this ...
<soap:Body> <PostNewOrderResponse xmlns="http://tempuri.org/" /> </soap:Body>
Interesting. So it threw a response node back at me. But what's very curious, is that when I call this method from code, I still get a void return and my input parameter does not get submitted "by reference" (which would indicate that the output is the same type as the input). Next I wondered if even though no response was returned, the HTTP 200 code would only return after the service had finished processing. But no, that wasn't the case (and wouldn't really make sense anyway). So, at this point, I can't say for sure that this makes ANY difference.
The next "one way" operation I tried was on an orchestration that had a request/response receive port. My thinking was that maybe this flag would make the service ignore the response. That is, it would open up a one-way SOAP channel into the orchestration, but, wouldn't wait for a response. I hypothesized that this response message might get suspended, or something like that. So, I built a service using the Web Services Publishing Wizard, flipped the Force Request Response to "no" and took a look at the output. And ... it's the exact same whether I flip that flag to "yes" or "no." Because the service is built with a return value, apparently you can't set the "oneway" flag to true. I tried changing that attribute in the generated service, and then my service wouldn't come up. Once again, I have no idea how this flag is supposed to be applied. Thoughts?
Now, let's switch to something that DOES work. If you're following best practices, you're probably putting your external-facing schemas in one project, and your internal schemas in another. Reason being, if your vendor changes something, and you've been smart enough to do all your transformations at the port level, you can isolate how many assemblies you have to change. So let's say you have a schema in this "external schemas assembly" that you've exposed using the Web Services Publishing Wizard by "generating web service from schemas." Now let's also say that ANOTHER schema in that assembly has changed, and you go ahead and redeploy a new version of that assembly and blow away the old one. Now your web service will cause your messages to be suspended.
When you use the generated web services, the DocumentSpecName is set on the inbound message by the web service. You can see this value in the message context here ...
Problem is, this value is used to look up the message type, and since the DocumentSpecName contains the full assembly reference, your message will get suspended if it can't find the specific version.
So how do you avoid this? What I've done is went into the generated web service, and changed the following value in my web method ...
//set to *null* and comment out old value
string bodyTypeAssemblyQualifiedName = null;
// "Microsoft.Demo.Blog.AdvancedServices.VTest.NewContact_XML, Microsoft.Demo.Blog.Ad" +
//"vancedServices.VTest, Version=22.214.171.124, Culture=neutral, PublicKeyToken=94858e0d889683c1";
Now, when messages come into BizTalk, the DocumentSpecName doesn't get set and BizTalk does a lookup on the namespace#root to find the appropriate schema and assembly.
So what have we seen? First, the Force Request Response flag has no obvious use to me. Doesn't seen to make a difference on existing one way services, and it can't be applied on request/response services. If I've missed something, please tell me. Also, we've seen how you can modify your generated web service to insulate you against assembly version changes. Always be careful changing generated code, and clearly you want to regenerate your service if the corresponding message schemas has changed, but, this eliminates your need to regenerate the service when unrelated schemas change in the assembly. Fun stuff.