This time I will talk about the importance of order within xml elements.
Let's say we have a web service with this schema:
So of course this is a valid request:
But about about this?
This is not a valid xml instance!
The reason is that the schema contains the element which requires its sub elements to have order.
So why is it an interoperability gotcha?
The reason is that different soap stacks by different vendors behave differently in such cases. Sometimes even different stacks of the same vendor are divided...
Let's see how a .Net 2.0 proxy would look like:
This proxy can parse both xml instances from above.
This is how the equivalent WCF proxy would look like:
This proxy is stricter and actually enforces the order of elements. So it would only accept the first (legal) instance and will give unexpected results with the second. It would usually not throw an exception but rather ignore the message and use default values for the unordered elements so your fields will have a lot of NULL's and zeros.
How to fix it?
Option 1 (recommended) - Send XML with the correct order.
Option 2 - Change the WSDL to use <all> instead of <sequence>. The former does not require correct order of elements (there are some other subtle differences). Note that in case the WSDL is dynamically generated this may be hard to maintain.
Option 3 - Remove the "Order=..." property from the WCF proxy. Note that when the proxy will be regenerated the "Order" property will come back so this is also a maintenance challenge.
When a custom binding is used in WCF it is possible to configure the value of requireSecurityContextCancellation. The name of this property doesn't exactly indicate in what scenarios it should be used.
When the client and server use WS-SecureConversation (by setting authenticationMode to "SecureConversation") the client get some token from the server in the initial handshake and needs to send it in every connection attempt. The server can extract this token and find the relevant data of this session in its memory. But what happens when the server/IIS is restarted? The memory is cleared and the session becomes invalid. The way to overcome this is to set requireSecurityContextCancellation to false (the default is true). In this mode the session key is saved at the client side and it sends it to the server in every request. This means that even if the server is restarted the session key is available in the request. This also means that the size of each request is a little bigger.
Since with this mode the server does not need to save the session key it does not need to be informed when the session is over and from here the property name requireSecurityContextCancellation.
Richard Blewett has published a great post about WCF sessions. He explains how sessions are implemented in each of the bindings and how they can be used.
One addition over this post is that sessions can also be used in WCF via the asp.net compatibility mode. Here, the way to access the session is:
In this mode the session is implemented via an HTTP cookie - exactly as with classic .Net 2.0 web services / asp.net. This means that this mode is available only when hosting in IIS and using HTTP transport. This mode should be used in case backward compatibility with an old service/client is required. It should not be used with new services as it adds some overhead to the pipeline.
Recently I had an interesting case with WCF "raw message" contract:
The message I used on the client side contained some SOAP headers. Since this is an untyped message these headers were neither encrypted nor signed. That was a show stopper for me.
However the request message was still not being encrypted nor signed. I struggled with this issue for some time until I was lucky enough to find Pedro Felix's message in the WCF MSDN forum:
In other words the OutgoingSignatureParts always relates to server outgoing messages while client outgoing stuff is always considered as "incoming". After fixing this the code worked like a charm. I probably should have proactively RTFM myself but at least I felt good for not being the only one who fell for this...
First attempt - using basicHttpBinding with MessageClientCredentialType of "Username". Unfortunetelly this would yield the following exception:
Second attempt - using basicHttpBinding with TransportWithMessageCredential mode.
Since this mode implies that we need to secure the transport we get any of these exceptions, depending if we are on the client or the server side:
Third attempt - using wsHttpBinding with MessageClientCredentialType of "Username".
Depending on several other settings, and wheather we're on the client or the server, we would get any of these exceptions:
Forth attempt - using wsHttpBinding with TransportWithMessageCredential mode.
Similarily to the second attempt we get:
OR
Fifth attempt - using customBinding with httpTransport and security element with authenticationMode of UserNameOverTransport
This time we get:
So it really seems like Microsoft is trying to (im)politely convince us not to use clear username/password. But what can we do for cases where this behaviour is really required?
The solution
The solution s to use ClearUsernameBinding. This binding seamlessly integrates with WCF and allows us to use clear username/password.