I’ve recently been working with an existing WCF service that does not properly export its metadata. [Note to WCF service developers: when testing your service, you need to explicitly test metadata export along with the actual service functionality. There are many ways to break it.] The Service Model Metadata Tool (a.k.a svcutil.exe) can connect to the service for metadata download (svcutil.exe /t:metadata <url>), but the result is a brief WSDL that contains no type information (no messages, no bindings, no schema at all).
The company that built the service uses the Web Services Contract First (WSCF) tool from Thinktecture to generate serializable .NET proxy classes and WSDL files from XML schemas. The service contract is defined by the XSD’s. [Note: WSCF does not directly support WCF.] Since we can’t download metadata from the service, the developers gave us a copy of their XSD’s and WSDL file (the latter generated by WSCF). Should be no problem to consume them.
In my case the service client is BizTalk Server 2006 R2, using its built-in support for WCF. BizTalk can generate a proxy (message and port types and schemas) for a service using the WCF Service Consuming Wizard. In a great example of unfriendly UI design, to reach this tool you must first have a BizTalk project open. Right-click the project and select “Add” then “Add Generated Items…”, then choose the “Consume WCF Service” option. The wizard can import directly from a running service, or it can import directly from a WSDL and associated XSD’s. The second option was perfect for our situation. Almost.
When I ran through the wizard, the wizard ended with the error “Error consuming WCF service metadata. Object reference not set to an instance of an object.” Not so good. One solution to this is quite simple, fortunately. There may be other variations in the WSDL or XSD’s that can cause the same error, but check this out first. In your WSDL file, make sure that the <xsd:schema> element has a targetNamespace attribute. It doesn’t matter what attribute value you use, just make sure it looks like <xsd:schema targetNamespace=”anything”>. The WSCF tool did not generate this attribute. Once it was in place, the wizard quickly generated the proper items in the project.
Another note: the WSCF-generated WSDL was also missing a <service> element. Without a service defined, BizTalk will generate empty binding files for the service. Be sure to include something like this in your WSDL:
<service name=”service1″>
<port name=”BasicHttpBinding_IService1″ binding=”tns:BindingName”>
<soap:address location=”http://localhost:8080/service1″ />
</port>
</service>
Make sure that the name in the binding attribute corresponds to the name attribute of your <binding> (or <wsdl:binding>) element, otherwise you’ll still end up with empty binding files.
When it’s working (most of the time), BizTalk 2006 R2 makes it really easy to both consume and publish WCF services. I’m glad that we are finally starting to move beyond the WSE and ASMX days!
Tom:
I noticed that you have some passing familiarity with WSCF. I’m using it on a customer project, and wondering if there’s some way you know of to add the WSE 3.0 pipeline to the service’s stack — so I can get turnkey security and MTOM.
Any idea if this is possible?
Thanks
Josh
josh.korn (at) diligentsia.com
Hi Josh,
I’m not exactly sure what you are referring to when you say “the service”, so I’ll assume you mean a WCF service out of BizTalk. There is no need for any WSE 3.0 components. WCF already provides support for MTOM and the WS-Security protocol (see wsHttpBinding). If you need exact compatibility with an existing WSE 3.0 client, you can create a custom WCF binding for that. If you are not talking about a BizTalk service, I would strongly push you to use WCF for the same reasons, except that you’d obviously be writing the service with regular .NET code. WSCF can be used to create WSDL which can in turn be converted to a WCF service interface with svcutil.exe from .NET 3.0/3.5.
I hope that helps. Thanks, Tom