/*============================================================================ ** ** ERG TRANSIT SYSTEMS Licensed software ** (C) 2008 All rights reserved ** **============================================================================ ** ** Project/Product : wsdl-tools ** Filename : WsdlExtract.cs ** Author(s) : David Purdie ** ** Description : Extract WSDLs from Managed Web Service DLL ** ** ** Information : ** Compiler : CSHARP 1 and 2 ** Target : Build Tools ** **==========================================================================*/ using System; using System.CodeDom; using System.CodeDom.Compiler; using System.Collections; using System.IO; using System.Reflection; using System.Web; using System.Web.Services; using System.Web.Services.Description; using System.Web.Services.Discovery; using System.Xml; using Microsoft.CSharp; namespace JATS.WsdlExtractor { /* ** Class to contain user command line options */ public class CmdLineParams { public string AssemblyName; public string OutDir = ""; public string Uri = "http://www.erggroup.com/"; public int Verbose = 0; public ArrayList EnvPath = new ArrayList(); /* ** Constructor */ public CmdLineParams() { /* ** Add default EnvVars to the EnvPath ** Cover all bases */ EnvPath.Add ("CS_LIB"); EnvPath.Add ("LIB"); EnvPath.Add ("PATH"); } } public class App { static CmdLineParams par = new CmdLineParams(); static CmdLineParams ParseCommandLine(string[] args) { /* ** Extract command line arguments - very simple ** Format: ** First must be assembly ** Remainder are program options of the form ** /x:value (value starts at value_index) ** or /x */ const int value_index = 3; par.AssemblyName = args[0]; for (int i = 1; i < args.Length; i++) { string arg = args[i]; if (arg[0] != '/') { throw new Exception("Incorrect command line parameter " + (i + 1) + " :" + arg); } switch (arg[1]) { case 'r': case 'R': par.Uri = arg.Substring(value_index); break; case 'p': case 'P': par.EnvPath.Insert( 0,arg.Substring(value_index)); break; case 'o': case 'O': par.OutDir = arg.Substring(value_index); break; case 'v': case 'V': par.Verbose += 1; break; default: throw new Exception("Incorrect command line parameter " + (i + 1) + " :" + arg); } } return par; } /* ** Main entry point */ static int Main(string[] args) { Console.WriteLine("Web Service WSDL Extractor"); /* ** Need at least one argument */ if (args.Length <= 1) { Console.WriteLine(@"Usage: WsdlExtract assembly [/r:URI] [/o:Basedir] [/p:EnvVar] [/v]"); Console.WriteLine(@""); Console.WriteLine(@"assembly - Path to Web Services DLL"); Console.WriteLine(@"/o:Output - Set Base Directory"); Console.WriteLine(@"/p:EnvVar - A path to search for required DLLs"); Console.WriteLine(@"/r:URI - Set web service XML namespace Uri"); Console.WriteLine(@"/v - Verbose. Multiple allowed"); return -1; } par = ParseCommandLine(args); try { /* ** Locate and load assembly DLL ** The assembly will load - even if it can't be used */ Assembly assembly = Assembly.LoadFrom(par.AssemblyName); /* ** Install an event handler to handle resolver events ** May be used to assist in determining DLLs that need to ** be loaded */ AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.AssemblyResolve += new ResolveEventHandler(MyResolveEventHandler); if (par.Verbose > 0 ) { /* ** Display a list of all assemblies references by the one just ** loaded. May be useful when determining problems */ Console.WriteLine("Referenced assemblies:"); foreach (AssemblyName an in assembly.GetReferencedAssemblies()) { Console.WriteLine(" " + an.ToString()); } } /* ** Find every type in the assembly that has a [WebMethod] ** Extract a WSDL if any of its methods are marked */ foreach (Module module in assembly.GetModules()) { foreach (Type type in module.GetTypes()) { bool hasWebMethod = false; foreach (MethodInfo method in type.GetMethods()) { if (method.GetCustomAttributes(typeof(WebMethodAttribute), false).Length > 0) { hasWebMethod = true; break; } } if (hasWebMethod) { ExtractWsdl(type, par.Uri, par.OutDir + type.Name + ".wsdl"); } } } } catch (Exception e) { Console.WriteLine(e); return -1; } return 0; } /// /// Given a web service type /// Extract the WSDL /// /// The web service type /// The URL for the service that will be set in the constructor /// The path to the .cs file that will be generated private static void ExtractWsdl(Type type, string uri, string path) { /* ** Load up the type and create a reflection */ ServiceDescriptionReflector reflector = new ServiceDescriptionReflector(); reflector.Reflect(type, uri); if (reflector.ServiceDescriptions.Count > 1) { throw new Exception(string.Format("Don't know how to deal with multiple service descriptions in {0}", type)); } // Write out the basic WSDL file reflector.ServiceDescriptions[0].Write(path); Console.WriteLine(" Extracted WSDL: {1} for {0}", type.FullName, path); } /* ** Event Handler: ResolveEvents ** Called when the Assembly Loader has tried all the normal avenues ** Atempt to locate the required DLL within the toolset library ** path. ** ** A bit ugly ** - Take the name of required assembly ** - Tac a .DLL to the end ** - Attempt to locate it in the configured EnvVar ** - If found, then load it ** - Check that its the correct version */ static Assembly MyResolveEventHandler(object sender, ResolveEventArgs args) { if (par.Verbose > 0 ) { Console.WriteLine("Need to Resolve: " + args.Name); } string Name = args.Name.Split(',')[0] + ".DLL"; foreach (string Var in par.EnvPath ) { if (par.Verbose > 0 ) Console.WriteLine("Use EnvVar: " + Var); string Path = Environment.GetEnvironmentVariable(Var); /* ** Ignore EnvVars that don't exist */ if ( Path == null ) continue; /* ** The EnvVar is a ; sep list of dirs ** Walk the list looking for a suitable DLL */ foreach (string dir in Path.Split(';') ) { if (par.Verbose > 0 ) Console.WriteLine(" Path:" + dir); if (File.Exists( dir + "\\" + Name ) ) { if (par.Verbose > 0 ) Console.WriteLine("" + Name + " Found in: " + dir); Assembly assembly = Assembly.LoadFrom(dir + "\\" + Name); if ( assembly != null ) { if (par.Verbose > 0 ) Console.WriteLine("" + Name + " Called: " + assembly.GetName()); if(String.Compare(assembly.GetName().FullName, args.Name) == 0) { return assembly; } if (par.Verbose > 0 ) { Console.WriteLine("Assembly Name Mismatch"); Console.WriteLine(" " + assembly.GetName().FullName); Console.WriteLine(" " + args.Name); } } } } } /* ** Not found ** Let the loader report the error */ return null; } } }