Showing posts with label gSOAP. Show all posts
Showing posts with label gSOAP. Show all posts

Saturday, January 29, 2011

gSoap and Wcf Routing Services are not friends

@YaronNaveh

One common patterns with web services is the router service. It can hide routing logic from the client or help with load balancing. Wcf 4 ships with libraries and samples to help build such a router very quickly.

Stephen Liedig had notified me recently on a problem which happens when a gSoap client calls a Wcf router. gSoap is a very popular CPP web services stack.

This was the deployment:



The gSoap client was sending this message to the router:

<soap:Envelope xmlns="http://tempuri.org/" xmlns:p="http://myNs/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 
<soap:Body>
   
<AddUser>
     
<user xsi:type="p:User">
       
<name>yaron</name>
     
</user>
   
</AddUser>
 
</soap:Body>
</soap:Envelope>


If the router would call the service using the http endpoint, everything would work. If it used the tcp endpoint, it could send the message, but the service implementation would never be called and the service would report this exception:


The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:user. The InnerException message was 'Element 'http://tempuri.org/:user' contains data of the ':User' data contract. The deserializer has no knowledge of any type that maps to this contract. Add the type corresponding to 'User' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.'.  Please see InnerException for more details.

Analysis

We need to ask two questions: Why this error happens? Why not with Http?

First we must take a look in the message that the router sent to the service. Here is how it appears in the Wcf log:

<soap:Envelope xmlns="http://tempuri.org/" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
 
<soap:Body>
   
<AddUser>
     
<user xsi:type="p:User">
       
<name>yaron</name>
     
</user>
   
</AddUser>
 
</soap:Body>
</soap:Envelope>


Something is missing – the “p” prefix declaration (xmlns:p=http://myNs/) which was present in the message form the client to the router does not appear. This makes this message invalid as it references the undeclared prefix "p" in the "p:User" derived type attribute. But why did the router sent an invalid message when the client sent it a good one? And why not with Http?

Let’s take a look at how Wcf routes messages. We can use the reflector to inspect System.ServiceModel.Routing.SoapProcessingBehavior+SoapProcessingInspector.MarshalMessage():

internal Message MarshalMessage(Message source, Uri to, MessageVersion targetVersion)
{
   
Message message;
   
MessageVersion version = source.Version;
   
if ((version == targetVersion) && !RoutingUtilities.IsMessageUsingWSSecurity(understoodHeaders))
   
{
       
...
       
return source;
   
}
   
...
   
else
   
{
       
XmlDictionaryReader readerAtBodyContents = source.GetReaderAtBodyContents();
       
message = Message.CreateMessage(targetVersion, headers.Action, readerAtBodyContents);
   
}

   
this.CloneHeaders(message.Headers, headers, to, understoodHeadersSet);    
   
return message;
}

Wcf uses this logic:

  • If the input message (from client) and output message (to server) have the same version, and no security is involved, then take the input as is and send it. This explains why the Http case works.
  • Otherwise take the input message body and copy it to a new message. Then copy custom user headers.

Since the “p” prefix is not defined under the body but under the root “envelope” element, this prefix is not sent which makes the message invalid. This explains the netTcp bug.

 

Why Wcf behaves in this way?

Dismissing this behavior as a bug will miss an important discussion. Consider the naïve fix: Parse each attribute under the body and search for the something:something pattern. Since the router has no information about the message semantics it has no way to know if the pattern relates to a prefix or is just a string which looks like this. Moreover doing this would be a huge performance hit, especially with big messages.

 

What should be the correct behavior?

In order to take both the functional and performance requirements into account, I would recommend the following approach:

  • Copy all namespace declarations from the root Envelope and Body elements of the original message into the corresponding elements of the new one (including the default namespace).
  • Make sure not to overload the previous prefixes with new definitions in both elements.

Yes, I can think of a few edge cases where this scheme fails. But a more comprehensive solution would cost in performance.


Conclusion

As it stands now, the default gSoap client fails to call the default Wcf router when protocol bridging is used, which is a real interoperability problem.

And Just to clarify, this web service does not define any derived (=inherited = known) types. For some reason the gSoap default message generation logic uses the xsi:type even on base types. This is  not forbidden since it uses the correct type name, although there is no real reason to do it. Anyway this makes this case quite common and not limited to services with derived types.

And, yes, this is one of the reasons not everyone likes Xml.

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!

Monday, October 27, 2008

Best Forums For Web Services Interoperability

@YaronNaveh

If you are writing a JAX-WS web service then you must be familiar with the Java.Net support forums. If you are a WCF developer you have surely bookmarked the MSDN forums. But what if you are an Axis2 developer seeking for interoperability with WCF? Or a .Net 2.0 tester having trouble with an XFire service? This post will give you a hint on where to ask your questions.

Axis2 / Rampart
If you need to work with an Axis2 service you can try to check if there is a bug already open on your case in the issues tracker:

http://issues.apache.org/jira/browse/AXIS2

You can drop a question at the WSO2 forums - This project is a server based upon Axis2 and developed by the same people who develope Axis2:

http://wso2.org/forum

Another good forum is the JavaRanch:

http://saloon.javaranch.com/cgi-bin/ubb/ultimatebb.cgi?ubb=forum&f=51

If you have a security question you better check in the Rampart (Axis2 security module) issues tracker:

http://issues.apache.org/jira/secure/BrowseProject.jspa?id=12310610

(You can also open a new issue as a "question")

Or again in WSO2

http://wso2.org/forum


Metro - JAX-WS - Tango - WSIT

JAX-WS is a standard Java interface for web services. Metro is a reference implementation of it written by Sun. Tango (=WSIT) adds WS-* support to Metro.

For this project the support is concentrated in the Metro forum:

http://forums.java.net/jive/forum.jspa?forumID=46

Or the binary web services forum:

http://forums.java.net/jive/forum.jspa?forumID=44


.Net 2.0 / WSE2 / WSE3
.Net 2.0 is the previous generation of Microsoft's web services stack. WSE2 and WSE3 are the WS-* implementation for .Net 2.0. The best places to ask on related issues are the Asp.Net XML web services forum:

http://forums.asp.net/28.aspx

And the MSDN forum:

http://social.msdn.microsoft.com/forums/en-US/asmxandxml/threads/


Windows Communication Foundation (WCF)
WCF is the latest generation of Microsoft's SOAP & WS-* stack. All related issues should go to the MSDN forum:

http://social.msdn.microsoft.com/forums/en-US/wcf/threads/


XFire / CXF
XFire is a Java Soap stack. Some time ago it has joined forces with Celtix to create a new Soap stack named CXF (CeltiXFire).

Questions should go to the mailing list:

http://www.nabble.com/cxf-user-f16914.html

If you still have question on old XFire go to nabble:

http://www.nabble.com/XFire-f8896.html


Spring-WS
Spring-WS is another Java soap stack. Here is its forum:

http://forum.springframework.org/forumdisplay.php?f=39

JBossWS
JBoss is a well known Java application server and it also has a web services framework:

http://www.jboss.com/index.html?module=bb&op=viewforum&f=200

gSOAP (C++)
gSoap is a familiar c++ soap stack. The discussion forum requires registration:

http://tech.groups.yahoo.com/group/gsoap/

But meanwhile you can open a support request or look at the open bugs:

http://sourceforge.net/tracker2/?group_id=52781

WSO2 WSF/ C / C++ / PHP / Ruby /...
WSO2 mentioned above also develop Axis2 compatible toolkits for various platforms. If you have a question on any of them you can ask here:

http://wso2.org/forum

If you have any additions to the list above please add a comment and I'll update it. Of course you're alwayes welcomed to share with us in this blog any interesting interoperability issue you have.

@YaronNaveh

What's next? get this blog rss updates or register for mail updates!