a575963da9
Former-commit-id: da6be194a6b1221998fc28233f2503bd61dd9d14
617 lines
16 KiB
C#
617 lines
16 KiB
C#
///
|
|
/// MonoWSDL.cs -- a WSDL to proxy code generator.
|
|
///
|
|
/// Author: Erik LeBel (eriklebel@yahoo.ca)
|
|
/// Lluis Sanchez (lluis@ximian.com)
|
|
///
|
|
/// Copyright (C) 2003, Erik LeBel,
|
|
///
|
|
|
|
#if !NET_2_0
|
|
|
|
using System;
|
|
using System.Collections.Specialized;
|
|
using System.Xml;
|
|
using System.Xml.Schema;
|
|
using System.Collections;
|
|
using System.CodeDom;
|
|
using System.CodeDom.Compiler;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Web.Services.Description;
|
|
using System.Web.Services.Discovery;
|
|
using System.Reflection;
|
|
|
|
using Microsoft.CSharp;
|
|
|
|
namespace Mono.WebServices
|
|
{
|
|
///
|
|
/// <summary>
|
|
/// Source code generator.
|
|
/// </summary>
|
|
///
|
|
class SourceGenerator
|
|
{
|
|
string applicationSiganture = null;
|
|
string appSettingURLKey = null;
|
|
string appSettingBaseURL = null;
|
|
string language = "CS";
|
|
string ns = null;
|
|
string outFilename = null;
|
|
string protocol = "Soap";
|
|
bool server = false;
|
|
|
|
///
|
|
/// <summary/>
|
|
///
|
|
public string Language
|
|
{
|
|
// FIXME validate
|
|
set { language = value; }
|
|
}
|
|
|
|
///
|
|
/// <summary/>
|
|
///
|
|
public string Namespace
|
|
{
|
|
set { ns = value; }
|
|
}
|
|
|
|
///
|
|
/// <summary>
|
|
/// The file to contain the generated code.
|
|
/// </summary>
|
|
///
|
|
public string Filename
|
|
{
|
|
set { outFilename = value; }
|
|
}
|
|
|
|
///
|
|
/// <summary/>
|
|
///
|
|
public string Protocol
|
|
{
|
|
// FIXME validate
|
|
set { protocol = value; }
|
|
get { return protocol; }
|
|
}
|
|
|
|
///
|
|
/// <summary/>
|
|
///
|
|
public string ApplicationSignature
|
|
{
|
|
set { applicationSiganture = value; }
|
|
}
|
|
|
|
///
|
|
/// <summary/>
|
|
///
|
|
public string AppSettingURLKey
|
|
{
|
|
set { appSettingURLKey = value; }
|
|
}
|
|
|
|
///
|
|
/// <summary/>
|
|
///
|
|
public string AppSettingBaseURL
|
|
{
|
|
set { appSettingBaseURL = value; }
|
|
}
|
|
|
|
///
|
|
/// <summary/>
|
|
///
|
|
public bool Server
|
|
{
|
|
set { server = value; }
|
|
}
|
|
|
|
///
|
|
/// <summary>
|
|
/// Generate code for the specified ServiceDescription.
|
|
/// </summary>
|
|
///
|
|
public bool GenerateCode (ArrayList descriptions, ArrayList schemas)
|
|
{
|
|
// FIXME iterate over each serviceDescription.Services?
|
|
CodeNamespace codeNamespace = GetCodeNamespace();
|
|
CodeCompileUnit codeUnit = new CodeCompileUnit();
|
|
bool hasWarnings = false;
|
|
|
|
codeUnit.Namespaces.Add(codeNamespace);
|
|
|
|
ServiceDescriptionImporter importer = new ServiceDescriptionImporter();
|
|
importer.ProtocolName = protocol;
|
|
if (server)
|
|
importer.Style = ServiceDescriptionImportStyle.Server;
|
|
|
|
foreach (ServiceDescription sd in descriptions)
|
|
importer.AddServiceDescription(sd, appSettingURLKey, appSettingBaseURL);
|
|
|
|
foreach (XmlSchema sc in schemas)
|
|
importer.Schemas.Add (sc);
|
|
|
|
ServiceDescriptionImportWarnings warnings = importer.Import(codeNamespace, codeUnit);
|
|
if (warnings != 0)
|
|
{
|
|
if ((warnings & ServiceDescriptionImportWarnings.NoCodeGenerated) > 0)
|
|
Console.WriteLine ("WARNING: No proxy class was generated");
|
|
if ((warnings & ServiceDescriptionImportWarnings.NoMethodsGenerated) > 0)
|
|
Console.WriteLine ("WARNING: The proxy class generated includes no methods");
|
|
if ((warnings & ServiceDescriptionImportWarnings.OptionalExtensionsIgnored) > 0)
|
|
Console.WriteLine ("WARNING: At least one optional extension has been ignored");
|
|
if ((warnings & ServiceDescriptionImportWarnings.RequiredExtensionsIgnored) > 0)
|
|
Console.WriteLine ("WARNING: At least one necessary extension has been ignored");
|
|
if ((warnings & ServiceDescriptionImportWarnings.UnsupportedBindingsIgnored) > 0)
|
|
Console.WriteLine ("WARNING: At least one binding is of an unsupported type and has been ignored");
|
|
if ((warnings & ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored) > 0)
|
|
Console.WriteLine ("WARNING: At least one operation is of an unsupported type and has been ignored");
|
|
hasWarnings = true;
|
|
}
|
|
|
|
string fileName = null;
|
|
bool hasBindings = false;
|
|
|
|
foreach (ServiceDescription desc in descriptions)
|
|
{
|
|
if (fileName == null && desc.Services.Count > 0)
|
|
fileName = desc.Services[0].Name;
|
|
|
|
if (desc.Bindings.Count > 0 || desc.Services.Count > 0)
|
|
hasBindings = true;
|
|
}
|
|
|
|
if (fileName == null)
|
|
fileName = "output";
|
|
|
|
if (hasBindings)
|
|
WriteCodeUnit (codeUnit, fileName);
|
|
|
|
return hasWarnings;
|
|
}
|
|
|
|
///
|
|
/// <summary>
|
|
/// Create the CodeNamespace with the generator's signature commented in.
|
|
/// </summary>
|
|
///
|
|
CodeNamespace GetCodeNamespace()
|
|
{
|
|
CodeNamespace codeNamespace = new CodeNamespace(ns);
|
|
|
|
if (applicationSiganture != null)
|
|
{
|
|
codeNamespace.Comments.Add(new CodeCommentStatement("\n This source code was auto-generated by " + applicationSiganture + "\n"));
|
|
}
|
|
|
|
return codeNamespace;
|
|
}
|
|
|
|
///
|
|
/// <summary/>
|
|
///
|
|
void WriteCodeUnit(CodeCompileUnit codeUnit, string serviceName)
|
|
{
|
|
CodeDomProvider provider = GetProvider();
|
|
ICodeGenerator generator = provider.CreateGenerator();
|
|
CodeGeneratorOptions options = new CodeGeneratorOptions();
|
|
|
|
string filename;
|
|
if (outFilename != null)
|
|
filename = outFilename;
|
|
else
|
|
filename = serviceName + "." + provider.FileExtension;
|
|
|
|
Console.WriteLine ("Writing file '{0}'", filename);
|
|
StreamWriter writer = new StreamWriter(filename);
|
|
generator.GenerateCodeFromCompileUnit(codeUnit, writer, options);
|
|
writer.Close();
|
|
}
|
|
|
|
///
|
|
/// <summary>
|
|
/// Fetch the Code Provider for the language specified by the 'language' members.
|
|
/// </summary>
|
|
///
|
|
private CodeDomProvider GetProvider()
|
|
{
|
|
CodeDomProvider provider;
|
|
Type type;
|
|
|
|
switch (language.ToUpper ()) {
|
|
case "CS":
|
|
provider = new CSharpCodeProvider ();
|
|
break;
|
|
case "VB":
|
|
provider = new Microsoft.VisualBasic.VBCodeProvider ();
|
|
break;
|
|
case "BOO":
|
|
type = Type.GetType("Boo.Lang.CodeDom.BooCodeProvider, Boo.Lang.CodeDom, Version=1.0.0.0, Culture=neutral, PublicKeyToken=32c39770e9a21a67");
|
|
if (type != null){
|
|
return (CodeDomProvider) Activator.CreateInstance (type);
|
|
}
|
|
throw new Exception ("Boo.Lang.CodeDom.BooCodeProvider not available");
|
|
|
|
default:
|
|
type = Type.GetType(language);
|
|
if (type != null) {
|
|
return (CodeDomProvider) Activator.CreateInstance (type);
|
|
}
|
|
throw new Exception ("Unknown language");
|
|
}
|
|
return provider;
|
|
}
|
|
}
|
|
|
|
///
|
|
/// <summary>
|
|
/// monoWSDL's main application driver. Reads the command-line arguments and dispatch the
|
|
/// appropriate handlers.
|
|
/// </summary>
|
|
///
|
|
public class Driver
|
|
{
|
|
const string ProductId = "Mono Web Services Description Language Utility";
|
|
const string UsageMessage =
|
|
"wsdl [options] {path | URL} \n\n"
|
|
+ " -d, -domain:domain Domain of username for server authentication.\n"
|
|
+ " -l, -language:language Language of generated code. Allowed CS (default)\n"
|
|
+ " and VB. You can also specify the fully qualified\n"
|
|
+ " name of a class that implements the\n"
|
|
+ " System.CodeDom.Compiler.CodeDomProvider Class.\n"
|
|
+ " -n, -namespace:ns The namespace of the generated code, default\n"
|
|
+ " namespace if none.\n"
|
|
+ " -nologo Surpress the startup logo.\n"
|
|
+ " -o, -out:filename The target file for generated code.\n"
|
|
+ " -p, -password:pwd Password used to contact the server.\n"
|
|
+ " -protocol:protocol Protocol to implement. Allowed: Soap (default),\n"
|
|
+ " HttpGet or HttpPost.\n"
|
|
+ " -server Generate server instead of client proxy code.\n"
|
|
+ " -u, -username:username Username used to contact the server.\n"
|
|
+ " -proxy:url Address of the proxy.\n"
|
|
+ " -pu, -proxyusername:username Username used to contact the proxy.\n"
|
|
+ " -pp, -proxypassword:pwd Password used to contact the proxy.\n"
|
|
+ " -pd, -proxydomain:domain Domain of username for proxy authentication.\n"
|
|
+ " -urlkey, -appsettingurlkey:key Configuration key that contains the default\n"
|
|
+ " url for the generated WS proxy.\n"
|
|
+ " -baseurl, -appsettingbaseurl:url Base url to use when constructing the\n"
|
|
+ " service url.\n"
|
|
+ " -type:typename,assembly Generate a proxy for a compiled web service\n"
|
|
+ " class. The URL parameter can be used to provide\n"
|
|
+ " the location of the service.\n"
|
|
+ " -sample:[binding/]operation Display a sample SOAP request and response.\n"
|
|
+ " -? Display this message\n"
|
|
+ "\n"
|
|
+ "Options can be of the forms -option, --option or /option\n";
|
|
|
|
SourceGenerator generator = null;
|
|
|
|
ArrayList descriptions = new ArrayList ();
|
|
ArrayList schemas = new ArrayList ();
|
|
|
|
bool noLogo = false;
|
|
bool help = false;
|
|
bool hasURL = false;
|
|
string sampleSoap = null;
|
|
|
|
string proxyAddress = null;
|
|
string proxyDomain = null;
|
|
string proxyPassword = null;
|
|
string proxyUsername = null;
|
|
string username;
|
|
string password;
|
|
string domain;
|
|
|
|
StringCollection urls = new StringCollection ();
|
|
string className;
|
|
|
|
///
|
|
/// <summary>
|
|
/// Initialize the document retrieval component and the source code generator.
|
|
/// </summary>
|
|
///
|
|
Driver()
|
|
{
|
|
generator = new SourceGenerator();
|
|
generator.ApplicationSignature = ProductId;
|
|
}
|
|
|
|
///
|
|
/// <summary>
|
|
/// Interperet the command-line arguments and configure the relavent components.
|
|
/// </summary>
|
|
///
|
|
void ImportArgument(string argument)
|
|
{
|
|
string optionValuePair;
|
|
|
|
if (argument.StartsWith("--"))
|
|
{
|
|
optionValuePair = argument.Substring(2);
|
|
}
|
|
else if (argument.StartsWith("/") || argument.StartsWith("-"))
|
|
{
|
|
optionValuePair = argument.Substring(1);
|
|
}
|
|
else
|
|
{
|
|
hasURL = true;
|
|
urls.Add (argument);
|
|
return;
|
|
}
|
|
|
|
string option;
|
|
string value;
|
|
|
|
int indexOfEquals = optionValuePair.IndexOf(':');
|
|
if (indexOfEquals > 0)
|
|
{
|
|
option = optionValuePair.Substring(0, indexOfEquals);
|
|
value = optionValuePair.Substring(indexOfEquals + 1);
|
|
}
|
|
else
|
|
{
|
|
option = optionValuePair;
|
|
value = null;
|
|
}
|
|
|
|
switch (option)
|
|
{
|
|
case "appsettingurlkey":
|
|
case "urlkey":
|
|
generator.AppSettingURLKey = value;
|
|
break;
|
|
|
|
case "appsettingbaseurl":
|
|
case "baseurl":
|
|
generator.AppSettingBaseURL = value;
|
|
break;
|
|
|
|
case "d":
|
|
case "domain":
|
|
domain = value;
|
|
break;
|
|
|
|
case "l":
|
|
case "language":
|
|
generator.Language = value;
|
|
break;
|
|
|
|
case "n":
|
|
case "namespace":
|
|
generator.Namespace = value;
|
|
break;
|
|
|
|
case "nologo":
|
|
noLogo = true;
|
|
break;
|
|
|
|
case "o":
|
|
case "out":
|
|
generator.Filename = value;
|
|
break;
|
|
|
|
case "p":
|
|
case "password":
|
|
password = value;
|
|
break;
|
|
|
|
case "protocol":
|
|
generator.Protocol = value;
|
|
break;
|
|
|
|
case "proxy":
|
|
proxyAddress = value;
|
|
break;
|
|
|
|
case "proxydomain":
|
|
case "pd":
|
|
proxyDomain = value;
|
|
break;
|
|
|
|
case "proxypassword":
|
|
case "pp":
|
|
proxyPassword = value;
|
|
break;
|
|
|
|
case "proxyusername":
|
|
case "pu":
|
|
proxyUsername = value;
|
|
break;
|
|
|
|
case "server":
|
|
generator.Server = true;
|
|
break;
|
|
|
|
case "u":
|
|
case "username":
|
|
username = value;
|
|
break;
|
|
|
|
case "sample":
|
|
sampleSoap = value;
|
|
break;
|
|
|
|
case "type":
|
|
case "t":
|
|
className = value;
|
|
break;
|
|
|
|
case "?":
|
|
help = true;
|
|
break;
|
|
|
|
default:
|
|
if (argument.StartsWith ("/") && argument.IndexOfAny (Path.InvalidPathChars) == -1) {
|
|
hasURL = true;
|
|
urls.Add (argument);
|
|
break;
|
|
}
|
|
else
|
|
throw new Exception("Unknown option '" + option + "'");
|
|
}
|
|
}
|
|
|
|
DiscoveryClientProtocol CreateClient ()
|
|
{
|
|
DiscoveryClientProtocol dcc = new DiscoveryClientProtocol ();
|
|
|
|
if (username != null || password != null || domain != null)
|
|
{
|
|
NetworkCredential credentials = new NetworkCredential();
|
|
|
|
if (username != null)
|
|
credentials.UserName = username;
|
|
|
|
if (password != null)
|
|
credentials.Password = password;
|
|
|
|
if (domain != null)
|
|
credentials.Domain = domain;
|
|
|
|
dcc.Credentials = credentials;
|
|
}
|
|
|
|
if (proxyAddress != null)
|
|
{
|
|
WebProxy proxy = new WebProxy (proxyAddress);
|
|
if (proxyUsername != null || proxyPassword != null || proxyDomain != null)
|
|
{
|
|
NetworkCredential credentials = new NetworkCredential();
|
|
|
|
if (proxyUsername != null)
|
|
credentials.UserName = proxyUsername;
|
|
|
|
if (proxyPassword != null)
|
|
credentials.Password = proxyPassword;
|
|
|
|
if (proxyDomain != null)
|
|
credentials.Domain = proxyDomain;
|
|
|
|
proxy.Credentials = credentials;
|
|
}
|
|
}
|
|
|
|
return dcc;
|
|
}
|
|
|
|
///
|
|
/// <summary>
|
|
/// Driver's main control flow:
|
|
/// - parse arguments
|
|
/// - report required messages
|
|
/// - terminate if no input
|
|
/// - report errors
|
|
/// </summary>
|
|
///
|
|
int Run(string[] args)
|
|
{
|
|
try
|
|
{
|
|
// parse command line arguments
|
|
foreach (string argument in args)
|
|
{
|
|
ImportArgument(argument);
|
|
}
|
|
|
|
if (noLogo == false)
|
|
Console.WriteLine(ProductId);
|
|
|
|
if (help || (!hasURL && className == null))
|
|
{
|
|
Console.WriteLine(UsageMessage);
|
|
return 0;
|
|
}
|
|
|
|
if (className == null) {
|
|
DiscoveryClientProtocol dcc = CreateClient ();
|
|
|
|
foreach (string urlEntry in urls) {
|
|
string url = urlEntry;
|
|
dcc.AllowAutoRedirect = true;
|
|
if (!url.StartsWith ("http://") && !url.StartsWith ("https://") && !url.StartsWith ("file://"))
|
|
url = new Uri (Path.GetFullPath (url)).ToString ();
|
|
|
|
dcc.DiscoverAny (url);
|
|
dcc.ResolveAll ();
|
|
}
|
|
|
|
foreach (object doc in dcc.Documents.Values) {
|
|
if (doc is ServiceDescription)
|
|
descriptions.Add ((ServiceDescription) doc);
|
|
else if (doc is XmlSchema)
|
|
schemas.Add ((XmlSchema) doc);
|
|
}
|
|
|
|
if (descriptions.Count == 0) {
|
|
Console.WriteLine ("Warning: no classes were generated.");
|
|
return 0;
|
|
}
|
|
} else {
|
|
string[] names = className.Split (',');
|
|
if (names.Length != 2) throw new Exception ("Invalid parameter value for 'type'");
|
|
string cls = names[0].Trim ();
|
|
string assembly = names[1].Trim ();
|
|
|
|
Assembly asm = Assembly.LoadFrom (assembly);
|
|
Type t = asm.GetType (cls);
|
|
if (t == null) throw new Exception ("Type '" + cls + "' not found in assembly " + assembly);
|
|
ServiceDescriptionReflector reflector = new ServiceDescriptionReflector ();
|
|
foreach (string url in urls)
|
|
reflector.Reflect (t, url);
|
|
foreach (XmlSchema s in reflector.Schemas)
|
|
schemas.Add (s);
|
|
|
|
foreach (ServiceDescription sd in reflector.ServiceDescriptions)
|
|
descriptions.Add (sd);
|
|
}
|
|
|
|
if (sampleSoap != null)
|
|
{
|
|
ConsoleSampleGenerator.Generate (descriptions, schemas, sampleSoap, generator.Protocol);
|
|
return 0;
|
|
}
|
|
|
|
// generate the code
|
|
generator.GenerateCode (descriptions, schemas);
|
|
return 0;
|
|
}
|
|
catch (NullReferenceException e)
|
|
{
|
|
Console.WriteLine (e);
|
|
return 2;
|
|
}
|
|
catch (InvalidCastException e)
|
|
{
|
|
Console.WriteLine (e);
|
|
return 2;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
Console.WriteLine("Error: {0}", exception.Message);
|
|
// FIXME: surpress this except for when debug is enabled
|
|
//Console.WriteLine("Stack:\n {0}", exception.StackTrace);
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
///
|
|
/// <summary>
|
|
/// Application entry point.
|
|
/// </summary>
|
|
///
|
|
public static int Main(string[] args)
|
|
{
|
|
Driver d = new Driver();
|
|
return d.Run(args);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endif
|