2 /// MonoWSDL.cs -- a WSDL to proxy code generator.
\r
4 /// Author: Erik LeBel (eriklebel@yahoo.ca)
\r
5 /// Lluis Sanchez (lluis@novell.com)
\r
7 /// Copyright (C) 2003, Erik LeBel,
\r
14 using System.Xml.Serialization;
\r
15 using System.Xml.Schema;
\r
16 using System.Collections;
\r
17 using System.Collections.Specialized;
\r
18 using System.CodeDom;
\r
19 using System.CodeDom.Compiler;
\r
22 using System.Web.Services.Description;
\r
23 using System.Web.Services.Discovery;
\r
24 using System.Web.Services;
\r
26 using Microsoft.CSharp;
\r
28 namespace Mono.WebServices
\r
32 string ProductId = "Web Services Description Language Utility\nMono Framework v" + Environment.Version;
\r
33 const string UsageMessage =
\r
34 "wsdl [options] {path | URL} {path | URL} ...\n\n"
\r
35 + " -d, -domain:domain Domain of username for server authentication.\n"
\r
36 + " -l, -language:language Language of generated code. Allowed CS (default)\n"
\r
37 + " and VB. You can also specify the fully qualified\n"
\r
38 + " name of a class that implements the\n"
\r
39 + " System.CodeDom.Compiler.CodeDomProvider Class.\n"
\r
40 + " -n, -namespace:ns The namespace of the generated code, default\n"
\r
41 + " namespace if none.\n"
\r
42 + " -nologo Surpress the startup logo.\n"
\r
43 + " -o, -out:filename The target file for generated code.\n"
\r
44 + " -p, -password:pwd Password used to contact the server.\n"
\r
45 + " -protocol:protocol Protocol to implement. Allowed: Soap (default),\n"
\r
46 + " HttpGet or HttpPost.\n"
\r
47 + " -fields Generate fields instead of properties in data\n"
\r
49 + " -server Generate server instead of client proxy code.\n"
\r
50 + " -u, -username:username Username used to contact the server.\n"
\r
51 + " -proxy:url Address of the proxy.\n"
\r
52 + " -pu, -proxyusername:username Username used to contact the proxy.\n"
\r
53 + " -pp, -proxypassword:pwd Password used to contact the proxy.\n"
\r
54 + " -pd, -proxydomain:domain Domain of username for proxy authentication.\n"
\r
55 + " -urlkey, -appsettingurlkey:key Configuration key that contains the default\n"
\r
56 + " url for the generated WS proxy.\n"
\r
57 + " -baseurl, -appsettingbaseurl:url Base url to use when constructing the\n"
\r
59 + " -sample:[binding/]operation Display a sample SOAP request and response.\n"
\r
60 + " -? Display this message\n"
\r
62 + "Options can be of the forms -option, --option or /option\n";
\r
64 ArrayList descriptions = new ArrayList ();
\r
65 ArrayList schemas = new ArrayList ();
\r
71 string proxyAddress;
\r
73 string proxyPassword;
\r
74 string proxyUsername;
\r
79 string applicationSignature;
\r
80 string appSettingURLKey;
\r
81 string appSettingBaseURL;
\r
82 string language = "CS";
\r
85 string protocol = "Soap";
\r
86 ServiceDescriptionImportStyle style;
\r
87 CodeGenerationOptions options = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync;
\r
90 StringCollection urls = new StringCollection ();
\r
94 /// Application entry point.
\r
97 public static int Main(string[] args)
\r
99 Driver d = new Driver();
\r
100 return d.Run(args);
\r
105 applicationSignature = ProductId;
\r
108 int Run (string[] args)
\r
112 // parse command line arguments
\r
113 foreach (string argument in args)
\r
114 ImportArgument(argument);
\r
116 if (noLogo == false)
\r
117 Console.WriteLine(ProductId);
\r
119 if (help || urls.Count == 0)
\r
121 Console.WriteLine(UsageMessage);
\r
125 CodeCompileUnit codeUnit = new CodeCompileUnit();
\r
126 CodeNamespace proxyCode = GetCodeNamespace();
\r
127 codeUnit.Namespaces.Add (proxyCode);
\r
129 WebReferenceCollection references = new WebReferenceCollection ();
\r
130 foreach (string murl in urls)
\r
132 DiscoveryClientProtocol dcc = CreateClient ();
\r
135 if (!url.StartsWith ("http://") && !url.StartsWith ("https://") && !url.StartsWith ("file://"))
\r
136 url = new Uri (Path.GetFullPath (url)).ToString ();
\r
138 dcc.DiscoverAny (url);
\r
141 WebReference reference = new WebReference (dcc.Documents, proxyCode, protocol, appSettingURLKey, appSettingBaseURL);
\r
142 references.Add (reference);
\r
144 if (sampleSoap != null)
\r
145 ConsoleSampleGenerator.Generate (descriptions, schemas, sampleSoap, protocol);
\r
148 if (sampleSoap != null)
\r
151 // generate the code
\r
152 GenerateCode (references, codeUnit);
\r
155 catch (Exception exception)
\r
157 Console.WriteLine("Error: {0}", exception.Message);
\r
159 // Supress this except for when debug is enabled
\r
160 Console.WriteLine("Stack:\n {0}", exception.StackTrace);
\r
167 /// Generate code for the specified ServiceDescription.
\r
170 public bool GenerateCode (WebReferenceCollection references, CodeCompileUnit codeUnit)
\r
172 bool hasWarnings = false;
\r
174 CodeDomProvider provider = GetProvider();
\r
176 StringCollection validationWarnings;
\r
177 validationWarnings = ServiceDescriptionImporter.GenerateWebReferences (references, options, style, provider, codeUnit, verbose);
\r
179 for (int n=0; n<references.Count; n++)
\r
181 WebReference wr = references [n];
\r
183 BasicProfileViolationCollection violations = new BasicProfileViolationCollection ();
\r
184 if (!WebServicesInteroperability.CheckConformance (WsiClaims.BP10, wr, violations)) {
\r
185 wr.Warnings |= ServiceDescriptionImportWarnings.WsiConformance;
\r
188 if (wr.Warnings != 0)
\r
190 if (!hasWarnings) {
\r
191 WriteText ("", 0, 0);
\r
192 WriteText ("There where some warnings while generating the code:", 0, 0);
\r
195 WriteText ("", 0, 0);
\r
196 WriteText (urls[n], 2, 2);
\r
198 if ((wr.Warnings & ServiceDescriptionImportWarnings.WsiConformance) > 0) {
\r
199 WriteText ("- This web reference does not conform to WS-I Basic Profile v1.0", 4, 6);
\r
200 foreach (BasicProfileViolation vio in violations) {
\r
201 WriteText (vio.NormativeStatement + ": " + vio.Details, 8, 8);
\r
202 foreach (string ele in vio.Elements)
\r
203 WriteText ("* " + ele, 10, 12);
\r
207 if ((wr.Warnings & ServiceDescriptionImportWarnings.NoCodeGenerated) > 0)
\r
208 WriteText ("- WARNING: No proxy class was generated", 4, 6);
\r
209 if ((wr.Warnings & ServiceDescriptionImportWarnings.NoMethodsGenerated) > 0)
\r
210 WriteText ("- WARNING: The proxy class generated includes no methods", 4, 6);
\r
211 if ((wr.Warnings & ServiceDescriptionImportWarnings.OptionalExtensionsIgnored) > 0)
\r
212 WriteText ("- WARNING: At least one optional extension has been ignored", 4, 6);
\r
213 if ((wr.Warnings & ServiceDescriptionImportWarnings.RequiredExtensionsIgnored) > 0)
\r
214 WriteText ("- WARNING: At least one necessary extension has been ignored", 4, 6);
\r
215 if ((wr.Warnings & ServiceDescriptionImportWarnings.UnsupportedBindingsIgnored) > 0)
\r
216 WriteText ("- WARNING: At least one binding is of an unsupported type and has been ignored", 4, 6);
\r
217 if ((wr.Warnings & ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored) > 0)
\r
218 WriteText ("- WARNING: At least one operation is of an unsupported type and has been ignored", 4, 6);
\r
220 hasWarnings = true;
\r
224 if (hasWarnings) WriteText ("",0,0);
\r
226 string filename = outFilename;
\r
227 bool hasBindings = false;
\r
229 foreach (object doc in references[0].Documents.Values)
\r
231 ServiceDescription desc = doc as ServiceDescription;
\r
232 if (desc == null) continue;
\r
234 if (desc.Services.Count > 0 && filename == null)
\r
235 filename = desc.Services[0].Name + "." + provider.FileExtension;
\r
237 if (desc.Bindings.Count > 0 || desc.Services.Count > 0)
\r
238 hasBindings = true;
\r
241 if (filename == null)
\r
242 filename = "output." + provider.FileExtension;
\r
245 WriteText ("Writing file '" + filename + "'", 0, 0);
\r
246 StreamWriter writer = new StreamWriter(filename);
\r
248 CodeGeneratorOptions compilerOptions = new CodeGeneratorOptions();
\r
249 provider.GenerateCodeFromCompileUnit (codeUnit, writer, compilerOptions);
\r
253 return hasWarnings;
\r
258 /// Create the CodeNamespace with the generator's signature commented in.
\r
261 CodeNamespace GetCodeNamespace()
\r
263 CodeNamespace codeNamespace = new CodeNamespace(ns);
\r
265 if (applicationSignature != null)
\r
267 codeNamespace.Comments.Add(new CodeCommentStatement("\n This source code was auto-generated by " + applicationSignature + "\n"));
\r
270 return codeNamespace;
\r
276 void WriteCodeUnit(CodeCompileUnit codeUnit, string serviceName)
\r
278 CodeDomProvider provider = GetProvider();
\r
279 ICodeGenerator generator = provider.CreateGenerator();
\r
280 CodeGeneratorOptions options = new CodeGeneratorOptions();
\r
283 if (outFilename != null)
\r
284 filename = outFilename;
\r
286 filename = serviceName + "." + provider.FileExtension;
\r
288 Console.WriteLine ("Writing file '{0}'", filename);
\r
289 StreamWriter writer = new StreamWriter(filename);
\r
290 generator.GenerateCodeFromCompileUnit(codeUnit, writer, options);
\r
296 /// Fetch the Code Provider for the language specified by the 'language' members.
\r
299 private CodeDomProvider GetProvider()
\r
301 CodeDomProvider provider;
\r
304 switch (language.ToUpper ()) {
\r
306 provider = new CSharpCodeProvider ();
\r
309 provider = new Microsoft.VisualBasic.VBCodeProvider ();
\r
312 type = Type.GetType("Boo.Lang.CodeDom.BooCodeProvider, Boo.Lang.CodeDom, Version=1.0.0.0, Culture=neutral, PublicKeyToken=32c39770e9a21a67");
\r
314 return (CodeDomProvider) Activator.CreateInstance (type);
\r
316 throw new Exception ("Boo.Lang.CodeDom.BooCodeProvider not available");
\r
319 type = Type.GetType(language);
\r
320 if (type != null) {
\r
321 return (CodeDomProvider) Activator.CreateInstance (type);
\r
323 throw new Exception ("Unknown language");
\r
332 /// Interperet the command-line arguments and configure the relavent components.
\r
335 void ImportArgument(string argument)
\r
337 string optionValuePair;
\r
339 if (argument.StartsWith("--"))
\r
341 optionValuePair = argument.Substring(2);
\r
343 else if (argument.StartsWith("/") || argument.StartsWith("-"))
\r
345 optionValuePair = argument.Substring(1);
\r
349 urls.Add (argument);
\r
356 int indexOfEquals = optionValuePair.IndexOf(':');
\r
357 if (indexOfEquals > 0)
\r
359 option = optionValuePair.Substring(0, indexOfEquals);
\r
360 value = optionValuePair.Substring(indexOfEquals + 1);
\r
364 option = optionValuePair;
\r
370 case "appsettingurlkey":
\r
372 appSettingURLKey = value;
\r
375 case "appsettingbaseurl":
\r
377 appSettingBaseURL = value;
\r
401 outFilename = value;
\r
414 proxyAddress = value;
\r
417 case "proxydomain":
\r
419 proxyDomain = value;
\r
422 case "proxypassword":
\r
424 proxyPassword = value;
\r
427 case "proxyusername":
\r
429 proxyUsername = value;
\r
433 style = ServiceDescriptionImportStyle.Server;
\r
446 options &= ~CodeGenerationOptions.GenerateProperties;
\r
450 sampleSoap = value;
\r
458 if (argument.StartsWith ("/") && argument.IndexOfAny (Path.InvalidPathChars) == -1) {
\r
459 urls.Add (argument);
\r
463 throw new Exception("Unknown option " + option);
\r
467 DiscoveryClientProtocol CreateClient ()
\r
469 DiscoveryClientProtocol dcc = new DiscoveryClientProtocol ();
\r
471 if (username != null || password != null || domain != null)
\r
473 NetworkCredential credentials = new NetworkCredential();
\r
475 if (username != null)
\r
476 credentials.UserName = username;
\r
478 if (password != null)
\r
479 credentials.Password = password;
\r
481 if (domain != null)
\r
482 credentials.Domain = domain;
\r
484 dcc.Credentials = credentials;
\r
487 if (proxyAddress != null)
\r
489 WebProxy proxy = new WebProxy (proxyAddress);
\r
490 if (proxyUsername != null || proxyPassword != null || proxyDomain != null)
\r
492 NetworkCredential credentials = new NetworkCredential();
\r
494 if (proxyUsername != null)
\r
495 credentials.UserName = proxyUsername;
\r
497 if (proxyPassword != null)
\r
498 credentials.Password = proxyPassword;
\r
500 if (proxyDomain != null)
\r
501 credentials.Domain = proxyDomain;
\r
503 proxy.Credentials = credentials;
\r
510 static void WriteText (string text, int initialLeftMargin, int leftMargin)
\r
513 int margin = initialLeftMargin;
\r
517 Console.WriteLine ();
\r
521 while (n < text.Length)
\r
524 int lastWhite = -1;
\r
526 while (col < maxCols && n < text.Length) {
\r
527 if (char.IsWhiteSpace (text[n]))
\r
533 if (lastWhite == -1 || col < maxCols)
\r
535 else if (col >= maxCols)
\r
538 Console.WriteLine (new String (' ', margin) + text.Substring (sn, lastWhite - sn));
\r
539 margin = leftMargin;
\r