UPDATE 4/12/2013: Tool included
Download WSDL Flattener Tool
I’m not including source because it’s messy (I prefer to cleanup my code before sharing…) but feel free to decompile with ILSpy if you don’t trust me.
UPDATE 8/11/2015: Command line tool included
WSDL Flattener Command Line Utility
Somehow I forgot to save my update – thanks Luke for pointing it out!
WCF is great – its flexible, standards compliant, super easy to work with, and just altogether nice. That is, until you try to use it with, say, Oracle products. WCF generates so-called modular wsdl files, with separate xsd files for types, and even sometimes multiple wsdl files. Not technically in violation of any standards, but kind-of pushing the limits.
There are plenty of articles out there about modifying a WCF service to generate a flat WSDL. Also if you upgrade to .NET 4.5, you can use the URL parameter ?singleWsdl to get a flattened WSDL.
But what if you don’t have control of the web service? What if you cannot upgrade or modify the code?
For some odd reason, Microsoft added the internal ability to generate a single WSDL but only exposed it through the WCF Service implementation. They didn’t add it to svcutil.exe, and they didn’t expose it in the Framework… publicly that is *evil grin*
Turns out, in the System.ServiceModel.Description namespace, there is an internal static class called “WsdlHelper”, and this class has a public static Method called “GetSingleWsdl” that takes a MetadataSet for a parameter, and returns a System.Web.Services.Description.ServiceDescription object representing the Wsdl as a single entity. All you have to do is call .Write(filename) and you have your file.
“But I don’t see any WsdlHelper class!!!!!!”
It’s internal – you have to use reflection to invoke it.
First, you have to load the metadata from the existing WCF service into a MetadataSet using a MetadataExchangeClient. (Hint: you will probably need to use a custom binding). Then you run that set into something like this:
var asy = System.Reflection.Assembly.GetAssembly(typeof(WsdlExporter)); Type t = asy.GetType("System.ServiceModel.Description.WsdlHelper", true); var method = t.GetMethod("GetSingleWsdl", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static); object retVal = method.Invoke(null, new object[] { metadataSet }); //cast retVal into System.Web.Services.Description.ServiceDescription, and call the .Write() method. All done
Using this, I was able to create a tool that takes a WCF url, and allows you to save a single .wsdl file. You want the tool? Later perhaps. For now put your thinking cap and Google gloves on, and write your own.