/*============================================================================
**
** 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;
}
}
}