A soap message may contain any number of user defined headers:
The list of possible headers may be defined in the wsdl:
we can see that:
1. MyHeader is a root level element in the schema so it cannot be optional (minOccurs=0).
2. The wsdl schema prohibits a minOccurs attribute on the "part" element.
So it seams every soap header is mandatory and cannot be omitted from the soap. Such a behavior is also the recommendation of the WSI basic profile.
Nevertheless, some frameworks (for example .Net 2.0 and WCF) do not force clients do send the headers nor do they enforce the existence of such on the server side. This results in the following interoperability guidelines:
When building a server, do not assume that all clients will always send all headers (e.g. check for null values)
Do not assume that all clients can omit headers (e.g. some client stacks require it). For this reason do not develop any logic which depends in the existence or absence of headers.
A common bug in .Net 2.0 may cause the following exception when compiling a proxy:
Microsoft did not fix this bug for Wcf so it also gives a similar exception:
Is this error limited to DateTime?
Not at all. You may also get any of these:
Or with your custom types.
What does this error mean?
For you – nothing. This is a .Net/Wcf bug.
When does this happen?
When the following conditions apply:
1. The wsdl (schema) declares a complex type C. 2. C contains a single element with maxOccures>1 (an array). 3. The wsdl declares an element e of type X with maxOccures>1.
Example:
What is the .Net bug?
The proxy will generate something like this:
This line declares an array of type DateTime[][], but also specifies that each item of the array is of type DateTime. Which is clearly an error since the array items are of type DateTime[] (this is a multidimentional array).
This is the reason why the proxy does not compile.
Workaround #1
Manually edit the proxy and change “typeof(DateTime)” to “typeof(DateTime[])”. This workaround is also described here.
Limitation: This change will be overridden every time you regenerate the proxy (update web/service reference).
Workaround #2
We mentioned that the bug only happens when the type C has one child element. Why not add it some friend so it would not be alone? This means we need to manually edit the wsdl. For example:
Now you may say this changes the schema and makes our proxy not valid. But note we have added an optional field only (minOccurs=0) so as long as we do not assign any value to it in our client this change is non-breaking.
Now let’s see how the proxy generated from the updated wsdl looks like:
Now .Net does not generate the multidimensional array in one shot, but declares the mediating type C. The proxy will in turn use this type as an array:
The following gotcha applies when the server is written in a Java framework (e.g. Axis) and the client is in .Net. When we "add service reference" in VS to create the client proxy from the wsdl we may get this error:
In order to understand what this means we need to take a look at some other (valid wsdl):
This means that the EchoString operation accepts a message that looks like that:
We might expect the proxy class to look something like that:
However the real proxy looks like this:
Why? The reason is that most wsdls use the "document/literal/wrapped" pattern. This means that the first element of the message ("EchoString" here) is just some wrapper that the user does not really care about. What our user cares about is the "s" parameter. So the proxy generated the more useful proxy.
But let's take a look at this schema:
Here the root element "EchoString" is not a dummy wrapper - it can take the form of a few types (since there is derivation). This means the proxy should not omit it.
So how does VS knows which proxy to create?
The answer is in the message definition in the wsdl:
Whenever the name of a part is "parameters" .Net assumed doc/lit/wrapped is used and generates the proxy accordingly. If even though the word "parameters" is used the wsdl is not doc/lit/wrapped (as in the last example) .Net may give us some error. Which error? You guessed correctly: "These members may not be derived". Now we can understand what the error means: .Net tries to omit the root element as it thinks doc/lit/wrapped is used. However this element cannot be removed since it is not dummy - it should be actively chosen by the user out of a few derived types.
Fix The way to fix it is open the wsdl in a text editor and change the part name from "parameters" to "parameters1". Now .Net will know to generate a doc/lit/bare proxy. This means a new wrapper class will appear as the root parameter in the proxy. While this may be a little more tedious api, this will not have any affect on the wire format and the proxy is fully interoperable.
However it is interesting to see how it is still relevant even a few years later when new frameworks are around.
The two common paradigms for building a web service are code-first and contract-first. The former means you start writing your c#/java/whatever service code and generate the contract (wsdl) from it. The latter means you first create the wsdl (either manually or using some tool) and then create the service code from it.
So with code-first you write this:
And this is auto generated for you:
While in contract-first you write the wsdl (possibly using a tool) and the code is generated.
Pros for code-first:
Developers are already familiar with code so development is faster. Being veteran developers, architects are also code-savvy.
More online resources
You'll need to use it anyway
Pros for contract first:
Better interoperability
Defers implementaiton details
You'll need to use it anyway
Code first is the de-facto "default setting" in almost all frameworks - most tutorials and documentation use it. So contract-first is much more interesting from a "let's write an interesting post" POV.
In the next series of posts I'll write on the contract-first approach using several frameworks.
My opinion on the matter is that it does not really matter. Contract-first is important from the interoperability perspective, but most frameworks do not support all wsdl/schema artifacts. So ignoring the code you'll find yourself working with a perfectly interoperable wsdl that no framework can consume. For example xsd:union is not supported in .Net and xsd:choice isn't in Axis2 1.3. Contract without an implementation is useless.
On the other hand, code-first also requires you to look in the generated wsdl and verify it is interoperable. A service that can't be consumed is also useless.
So code-first or contract-first? Whatever, you'll need to do both anyway.
The following interoperability issue can happen with a .Net 3.5 clients and older web services from various platforms (including Java. and .Net)
Everyone knows that Visual Studio 2008 has a build-in support for WCF which is the latest generation of Microsoft soap stack. By default, when writing web service clients in VS 2008 a WCF-flavored proxy is generated. However WCF only supports a subset of XML schema and WSDL patterns. For example it does not support RPC/Encoded WSDLs and XML attributes. Many older WSDLs use RPC/Encoded. With such WSDLs WCF is supposed to gracefully downgrade itself to .Net 2.0 which does support these WSDLs. I have noticed that in some cases this does not happen correctly. The result can be web service methods returning null instead of values.
The solution for such cases is to manually instruct VS 2008 to use its backward compatible proxy. All you need to do is:
Sometimes when you "add service reference" in VS 2008 you will get a few warnings (see below). When using svcutil like this:
these warnings may appear as errors.
If you get these errors/warnings:
Then (usually) you have nothing to worry about. What they mean is that your WSDL contains a binding which uses HTTP Post transport. For example:
WCF does not support this binding and so raised an error. So why you have nothing to worry about? The reason is that usually when a WSDL contains a HTTP Post binding it also contains a SOAP one and WCF can work with it. For example:
Actually you can see that even though errors have occured a functioning proxy was still generated.
Note that if you create a .NET 2.0 (asmx) web service then there is a configuration to determine if a HTTP Post binding should be created. I can't find it now but promise to post the details later on...
WSE is the previous generation of Microsoft WS-* stack. For this reasons a lot of Microsoft shops are in a need to interop between WSE & WCF. I'm not going to invent the wheel here - there's a great article in MSDN on this.
There is one delicate point I'd like to emphasize. WCF supports WS-Policy which is a way for a service to specify what WS-* requirements it has (e.g. security, attachments). The policy is contained inside the wsdl:
When a WCF client is generated using "Add service reference" the app.config is automatically synchronized with the WS-Policy from the service wsdl.
WSE does not support this usage of WS-Policy in any of its versions. So when a wsdl that was created using WSE is imported using WCF the app.config needs to be updated manually (or via the config editor). One exception is SSL which WCF can identify from the service url.
For a WSE WSDL, WCF generats a basicHttpBinding by default. In most cases a customBinding would be required in order to reach interoperability on the wire using rich security options, soap12 and MTOM.
I recently saw an error that a WSE server returned for a WCF client:
A short investigation showed that the WCF client used the auto-generated app.config with its basicHttpBinding. That's why it did't send any WS-Addressing headers as the error indicates. The solution is of course to manually edit app.config and move to an appropriate customBinding.
Every wsdl has a "style" and an "encoding". They only set the soap message format on-the-wire so they do not matter for the most developers most of the time. However it is highly recommended to always use style=document and encoding=literal to increase interoperability. For example:
There is a special recommended style to write doc/lit wsdls: doc/lit/wrapped. In this format each message is named with the operation name suffixed by "request" or "response". The message contains only one part named "parameters" (this name never appears in the soap in doc/lit so it shouldn't matter). There are other requirements - see more details at Anne's blog. For example (pseudo wsdl):
There are a few advantages to doc/lit/wrapped among them a cleaner model and a more expressive soap message. However this style raises a few interoperability issues:
Axis2 code generation If you've read Anne's explanation you know that the root element in the message is redundant (since it always has to be used anyway) and so the generated stub looks more complex than it should. Keith explains how to solve this.
WCF DataContractSerializer WCF has a few flavours of serializers. DataContractSerializer is the recommended one. However this serializer can only be used in doc/lit/wrapped. So If your use svcutil to generate a proxy like this:
You might get the following error:
You will get this error if your wsdl does not comply to doc/lit/wrapped in one or more ways. For example if your part names are not "parameters". The way to solve this is either to change the part names to "parameters" (and fix all other issues) or to not force svcutil to use DataContractSerializer:
In this case WCF will downgrade itself to use the .Net 2.0 XmlSerializer. This serializer is not bad at all and was used in .Net 2.0 applications. It does have a less optimal performance than the new serializer but you can use it in production applications if you need. Dan wrote an interesting comparison of the two serializers.
.Net 2.0 derived types I won't dive into details with this one. Generally speaking .Net 2.0 might try to serialize as doc/lit/wrapped some wsdls which are not really in this format and so it can fail code generation. One example is when the wrapper element has derived types.
Recently I was getting an error from a web service indicating that my request is invalid. I looked at my request:
And at the schema:
And it seemed valid to me.
So I asked the service provider to show me an example of a working soap request. And so he did:
You can see that the difference is in the namespace of the inner "name" element: It is from the "http://someOrganization" namespace in my request but from the empty namespace in the working request. For those of you less familiar with xml namespaces: In the previous request "xmlns" defined a default namespace for all elements without prefixes; In this case only elements that explicitly use the "ns" prefix belong to the namespace.
After a short investigation the cause of this was identified. Let's take a second look at the schema (which is a part of the wsdl file):
elementFormDefault can have 2 values:
unqualified means that non top level elements should appear as belonging to the empty namespace
qualified means that every element should appear as belonging to the targetNamespace of its defining schema
So my request was valid for the "qualified" option and the provider sample was valid for "unqualified". Since the wsdl contains "qualified" my request is correct after all.
However - as in many times with interoperability - there is a Gotcha:
Many web services frameworks poorly implement elementFormDefault
This effectively means that a server can use "unqualified" format even though the wsdl has "qualified".
The solutions can be:
1. Fix the server implementation 2. Manually change "qualified" to "unqualified" in the wsdl and recreate your client stubs.
For new services it is recommended to use "qualified" which is also the default for most new soap stacks.
Your service WSDL file is the contract between you and your web service clients. Whether you manually write the WSDL or let your framework automatically generate it for you - you want to make sure it is valid (otherwise you'l have no clients!).
There is more than one way to define the validity of a WSDL: Does it need to be valid according the WSDL XML schema? Does it need to comply to known best practices? Does it need to be parsed correctly by common soap stacks? There are different ways to test each of these requirements. Commercial tools, like XMLSpy, can help you with some. Today I'll show you a free alternative: the WSI test tool. WSI is the web services interoperability organization and it has defined the WSDL "basic profile" - a set of best practice recommendations for WSDLs. They have also published a tool that can tell you if your WSDL confirms to this profile and today I'll show you how to use it.
Step 1 - Download the WSI test tool
Go to the downloads page in the WSI site and download "Interoperability Testing Tools 1.1". It has a C# and a Java version - today we will use the C# one but using the Java is similar.
Step 2 - Extract the tool
Just extract the zip to some folder
Step 3 - Configure the test
Copy wsi-test-tools\cs\samples\analyzerConfig.xml to wsi-test-tools\cs\bin and open it with a text editor. Change the following values:
wsdlURI - Should contain the url for your wsdl, for example http://MyServer/MyService.asmx?WSDL
serviceLocation - Should contain the url for your service, for example http://MyServer/MyService.asmx
wsdlElement - This is the most confusing one. Your service has at least one endpoint/port. Here you need to define which one you currently want to test. In order to supply this data open your WSDL in internet explorer and notice that its structure is something like:
So take the value of the "targetNamespace" from here and put its value in the "namespace" attribute of the "wsdlElement" element in the configuration. Also take the value of the "name" element and put it in the "wsdlElement" element value. So the "wsdlElement" configuration may look like:
Note: If you have a few "wsdl:Binding" in your wsdl you should repeat this for each one.
Step 4 - Run the test
Open command line and go to the wsi-test-tools\cs\bin directory. Then run:
Step 5 - Analyze the results
The wsi-test-tools\cs\bin folder now contains a file report.xml. Open it in internet explorer to view the results.
So, you want to write an Axis2 web service and have .Net WCF clients too? Or maybe you already have a .Net 2.0 endpoint and want it to be consumed by WSIT? Yes, that’s possible, but there is some important stuff you should know about. Whether you are a .Net WCF, AXIS2, Metro or any other framework developer/tester – you want to stay tuned for this series.
Arun came up with an interesting interoperability issue for WSDL's without SoapAction. SoapAction is an on-the-wire-acronym for web service operations. For example in a web service "Calculator" the operation "Add" can have a SoapAction of "http://myService/Add" (but any arbitrary name can be used). Here is how this appears in the wsdl:
An issue arises when no SoapAction appears: Should we use an empty SoapAction or a default one? Arun explains how this is handled in WSIT (Tango) and WCF. The conclusion is to always explicitly declare a SoapAction for all operations. If your framework generates the WSDL for you - make sure you annotate it correctly so it emit this information.