Monday, August 22, 2011

Fun with WCF, WSDL & the F5 (Updated)

So this week we pushed out an early iteration of the latest version of our integration tool to a customer as a proof-of-concept for evaluation.  One of the features they were most interested in evaluating is the web service interface.  Our current customers interact with the existing version of the integration tool through FTP and a UI. 

Although the backend functionality is fairly stable, the web service layer itself is not that mature.  Not too big a deal as it’s a fairly thin wrapper over our existing service layer.  We created, tested and delivered a test .NET client that seemed to work fine and so were reasonably confident that there wouldn’t be too many hiccups.

Not so much.  We spent the better part of the day simply trying to get their tool to retrieve and understand our WSDL.  The good news is that we finally got it to work.

First the parameters:

  • We developed the web service using WCF, letting it auto-generate the WSDL.
  • We host our web service behind an F5 SSL proxy.
  • They were using a Java client.

To retrieve the WSDL from a WCF web service you use the URL https://mywebserver.com/mywebservice.svc?WSDL (we only accept SSL).  WCF the generates the WSDL on the fly.  By default, the WSDL it generates is a multi-file WSDL that separates the XSDs out into separate files and thus multiple calls.  The WSDL itself only contains schema import tags.  The import tags reference the service again in the form of http://mywebserver.com/mywebservice.svc?xsd=xsd{n} where {n} is a sequential number of the individual XSD definitions.  In our case we had 3.

The F5 was the first obstacle.  It acts as an SSL proxy.  By that, it terminates and decrypts the HTTPS request at the DMZ and passes along a HTTP request to the web server.  Thus, if a customer hits https://mywebserver.com/mywebservice.svc, the F5 will decrypt the request and pass it to the web server as http://mywebserver.com/mywebservice.svc.  That’s all fine and dandy until the web service generates the WSDL and sets the XSD import URLs.  Because it thinks that it’s communicating over HTTP, it generates XSD import references as HTTP.  When the client tries to resolve these it fails because the F5 rejects the HTTP requests.

Now based on research regarding another issue, I had thought that this might actually be an issue, however, I had tested it with Visual Studio (2008 and 2010) and both seemed to successfully resolve the imports.  Unfortunately, our customer’s java client balked.  They actually had a .NET test tool that did resolve the imports, however, it would only test against the endpoint address supplied by the WSDL, which of course was HTTP and choked.  It wouldn’t allow us to manually change it to HTTPS. Not that that would have helped since ultimately they needed to use the Java client.

After reading Josh Rack’s blog article on WCF, SSL and an F5, I performed a fix by saving the automatically generated WSDL and XSD files to a customer accessible folder on the web server.  I hand modified the XSD references in the four files to point to the files and set all references and the endpoint address to HTTPS. 

At this point our customer’s web service client was able to properly read the WSDL and resolve the XSD imports.  However, it was still having errors.  A little more Googling and I came across an MSDN article on ASMX Client with a WCF Service.  The gist of this article is that by default, WCF uses a serializer (DataContractSerializer) to serialize the service definition to XML that is optimized for a WCF client (although my understanding is that it is standards based and should be supported).  By overriding the default serializer, and using the XMLSerializer by specifying the  XmlSerilizerFormat attribute for the service contract as follows, non-WCF clients have a happier time consuming the service.

[ServiceContract, XmlSerializerFormat]
public interface IMyWebService
{
    [OperationContract]
    double GetData(int recordId);
}

At this point, our customer was finally able to connect to our web service and successfully call the methods.  However, this still leaves us with a couple of loose ends. 

The first is that we’re now having to manage WSDL files to solve the HTTPS/HTTP issue.  Fine for now but not a good long term solution.  The other is that some SOAP clients can’t process multi-file WSDLs.  Although our customer didn’t have that problem, it will only be a matter of time before someone does.

Both of these problems can be solved by creating a custom WSDL export extension that implements the IWsdlExportExtension interface.  I have yet to do this but have found a promising open source project, WCFExtras on CodePlex that does.  A quick scan of the code indicates that it shouldn’t be too hard to implement.

After that, the next problem is WS-* authentication behind the F5.  I’ll keep you informed.

[Update]

The WCFExtras mentioned above does in fact solve the WSDL http reference problem as well as having the ability to return single file WSDL.

You can also read my last post that details how to setup a test environment to simulate the F5 reverse proxy.

No comments:

Post a Comment