1 /// 2 /// MonoWSDL.cs -- a WSDL to proxy code generator. 3 /// 4 /// Author: Erik LeBel (eriklebel@yahoo.ca) 5 /// Lluis Sanchez (lluis@novell.com) 6 /// 7 /// Copyright (C) 2003, Erik LeBel, 8 /// 9 10 11 using System; 12 using System.Xml; 13 using System.Xml.Serialization; 14 using System.Xml.Schema; 15 using System.Collections; 16 using System.Collections.Specialized; 17 using System.CodeDom; 18 using System.CodeDom.Compiler; 19 using System.IO; 20 using System.Net; 21 using System.Web.Services.Description; 22 using System.Web.Services.Discovery; 23 using System.Web.Services; 24 25 using Microsoft.CSharp; 26 27 namespace Mono.WebServices 28 { 29 public class Driver 30 { 31 string ProductId = "Web Services Description Language Utility\nMono Framework v" + Environment.Version; 32 const string UsageMessage = 33 "wsdl [options] {path | URL} {path | URL} ...\n\n" 34 + " -d, -domain:domain Domain of username for server authentication.\n" 35 + " -l, -language:language Language of generated code. Allowed CS (default)\n" 36 + " and VB. You can also specify the fully qualified\n" 37 + " name of a class that implements the\n" 38 + " System.CodeDom.Compiler.CodeDomProvider Class.\n" 39 + " -n, -namespace:ns The namespace of the generated code, default\n" 40 + " namespace if none.\n" 41 + " -nologo Surpress the startup logo.\n" 42 + " -o, -out:filename The target file for generated code.\n" 43 + " -p, -password:pwd Password used to contact the server.\n" 44 + " -protocol:protocol Protocol to implement. Allowed: Soap (default),\n" 45 + " HttpGet or HttpPost.\n" 46 + " -fields Generate fields instead of properties in data\n" 47 + " classes.\n" 48 + " -server Generate server instead of client proxy code.\n" 49 + " -u, -username:username Username used to contact the server.\n" 50 + " -proxy:url Address of the proxy.\n" 51 + " -pu, -proxyusername:username Username used to contact the proxy.\n" 52 + " -pp, -proxypassword:pwd Password used to contact the proxy.\n" 53 + " -pd, -proxydomain:domain Domain of username for proxy authentication.\n" 54 + " -urlkey, -appsettingurlkey:key Configuration key that contains the default\n" 55 + " url for the generated WS proxy.\n" 56 + " -baseurl, -appsettingbaseurl:url Base url to use when constructing the\n" 57 + " service url.\n" 58 + " -sample:[binding/]operation Display a sample SOAP request and response.\n" 59 + " -? Display this message\n" 60 + "\n" 61 + "Options can be of the forms -option, --option or /option\n"; 62 63 ArrayList descriptions = new ArrayList (); 64 ArrayList schemas = new ArrayList (); 65 66 bool noLogo; 67 bool help; 68 string sampleSoap; 69 70 string proxyAddress; 71 string proxyDomain; 72 string proxyPassword; 73 string proxyUsername; 74 string username; 75 string password; 76 string domain; 77 78 string applicationSignature; 79 string appSettingURLKey; 80 string appSettingBaseURL; 81 string language = "CS"; 82 string ns; 83 string outFilename; 84 string protocol = "Soap"; 85 ServiceDescriptionImportStyle style; 86 CodeGenerationOptions options = CodeGenerationOptions.GenerateProperties | CodeGenerationOptions.GenerateNewAsync; 87 bool verbose; 88 89 StringCollection urls = new StringCollection (); 90 91 /// 92 /// <summary> 93 /// Application entry point. 94 /// </summary> 95 /// Main(string[] args)96 public static int Main(string[] args) 97 { 98 Driver d = new Driver(); 99 return d.Run(args); 100 } 101 Driver()102 Driver() 103 { 104 applicationSignature = ProductId; 105 } 106 Run(string[] args)107 int Run (string[] args) 108 { 109 try 110 { 111 // parse command line arguments 112 foreach (string argument in args) 113 ImportArgument(argument); 114 115 if (noLogo == false) 116 Console.WriteLine(ProductId); 117 118 if (help || urls.Count == 0) 119 { 120 Console.WriteLine(UsageMessage); 121 return 0; 122 } 123 124 CodeCompileUnit codeUnit = new CodeCompileUnit(); 125 CodeNamespace proxyCode = GetCodeNamespace(); 126 codeUnit.Namespaces.Add (proxyCode); 127 128 WebReferenceCollection references = new WebReferenceCollection (); 129 130 DiscoveryClientProtocol dcc = CreateClient (); 131 132 foreach (string murl in urls) 133 { 134 135 string url = murl; 136 if (!url.StartsWith ("http://") && !url.StartsWith ("https://") && !url.StartsWith ("file://")) 137 url = new Uri (Path.GetFullPath (url)).ToString (); 138 139 dcc.DiscoverAny (url); 140 dcc.ResolveAll (); 141 142 } 143 144 WebReference reference = new WebReference (dcc.Documents, proxyCode, protocol, appSettingURLKey, appSettingBaseURL); 145 references.Add (reference); 146 147 if (sampleSoap != null) 148 ConsoleSampleGenerator.Generate (descriptions, schemas, sampleSoap, protocol); 149 150 if (sampleSoap != null) 151 return 0; 152 153 // generate the code 154 GenerateCode (references, codeUnit); 155 return 0; 156 } 157 catch (Exception exception) 158 { 159 Console.WriteLine("Error: {0}", exception.Message); 160 161 // Supress this except for when debug is enabled 162 Console.WriteLine("Stack:\n {0}", exception.StackTrace); 163 return 2; 164 } 165 } 166 167 /// 168 /// <summary> 169 /// Generate code for the specified ServiceDescription. 170 /// </summary> 171 /// GenerateCode(WebReferenceCollection references, CodeCompileUnit codeUnit)172 public bool GenerateCode (WebReferenceCollection references, CodeCompileUnit codeUnit) 173 { 174 bool hasWarnings = false; 175 176 CodeDomProvider provider = GetProvider(); 177 178 StringCollection validationWarnings; 179 WebReferenceOptions opts = new WebReferenceOptions (); 180 opts.CodeGenerationOptions = options; 181 opts.Style = style; 182 opts.Verbose = verbose; 183 validationWarnings = ServiceDescriptionImporter.GenerateWebReferences (references, provider, codeUnit, opts); 184 185 for (int n=0; n<references.Count; n++) 186 { 187 WebReference wr = references [n]; 188 189 BasicProfileViolationCollection violations = new BasicProfileViolationCollection (); 190 if (String.Compare (protocol, "SOAP", StringComparison.OrdinalIgnoreCase) == 0 && !WebServicesInteroperability.CheckConformance (WsiProfiles.BasicProfile1_1, wr, violations)) { 191 wr.Warnings |= ServiceDescriptionImportWarnings.WsiConformance; 192 } 193 194 if (wr.Warnings != 0) 195 { 196 if (!hasWarnings) { 197 WriteText ("", 0, 0); 198 WriteText ("There were some warnings while generating the code:", 0, 0); 199 } 200 201 WriteText ("", 0, 0); 202 WriteText (urls[n], 2, 2); 203 204 if ((wr.Warnings & ServiceDescriptionImportWarnings.WsiConformance) > 0) { 205 WriteText ("- This web reference does not conform to WS-I Basic Profile v1.1", 4, 6); 206 foreach (BasicProfileViolation vio in violations) { 207 WriteText (vio.NormativeStatement + ": " + vio.Details, 8, 8); 208 foreach (string ele in vio.Elements) 209 WriteText ("* " + ele, 10, 12); 210 } 211 } 212 213 if ((wr.Warnings & ServiceDescriptionImportWarnings.NoCodeGenerated) > 0) 214 WriteText ("- WARNING: No proxy class was generated", 4, 6); 215 if ((wr.Warnings & ServiceDescriptionImportWarnings.NoMethodsGenerated) > 0) 216 WriteText ("- WARNING: The proxy class generated includes no methods", 4, 6); 217 if ((wr.Warnings & ServiceDescriptionImportWarnings.OptionalExtensionsIgnored) > 0) 218 WriteText ("- WARNING: At least one optional extension has been ignored", 4, 6); 219 if ((wr.Warnings & ServiceDescriptionImportWarnings.RequiredExtensionsIgnored) > 0) 220 WriteText ("- WARNING: At least one necessary extension has been ignored", 4, 6); 221 if ((wr.Warnings & ServiceDescriptionImportWarnings.UnsupportedBindingsIgnored) > 0) 222 WriteText ("- WARNING: At least one binding is of an unsupported type and has been ignored", 4, 6); 223 if ((wr.Warnings & ServiceDescriptionImportWarnings.UnsupportedOperationsIgnored) > 0) 224 WriteText ("- WARNING: At least one operation is of an unsupported type and has been ignored", 4, 6); 225 226 hasWarnings = true; 227 } 228 } 229 230 if (hasWarnings) WriteText ("",0,0); 231 232 string filename = outFilename; 233 bool hasBindings = false; 234 235 foreach (object doc in references[0].Documents.Values) 236 { 237 ServiceDescription desc = doc as ServiceDescription; 238 if (desc == null) continue; 239 240 if (desc.Services.Count > 0 && filename == null) 241 filename = desc.Services[0].Name + "." + provider.FileExtension; 242 243 if (desc.Bindings.Count > 0 || desc.Services.Count > 0) 244 hasBindings = true; 245 } 246 247 if (filename == null) 248 filename = "output." + provider.FileExtension; 249 250 if (hasBindings) { 251 WriteText ("Writing file '" + filename + "'", 0, 0); 252 StreamWriter writer = new StreamWriter(filename); 253 254 CodeGeneratorOptions compilerOptions = new CodeGeneratorOptions(); 255 provider.GenerateCodeFromCompileUnit (codeUnit, writer, compilerOptions); 256 writer.Close(); 257 } 258 259 return hasWarnings; 260 } 261 262 /// 263 /// <summary> 264 /// Create the CodeNamespace with the generator's signature commented in. 265 /// </summary> 266 /// GetCodeNamespace()267 CodeNamespace GetCodeNamespace() 268 { 269 CodeNamespace codeNamespace = new CodeNamespace(ns); 270 271 if (applicationSignature != null) 272 { 273 codeNamespace.Comments.Add(new CodeCommentStatement("\n This source code was auto-generated by " + applicationSignature + "\n")); 274 } 275 276 return codeNamespace; 277 } 278 279 /// 280 /// <summary/> 281 /// WriteCodeUnit(CodeCompileUnit codeUnit, string serviceName)282 void WriteCodeUnit(CodeCompileUnit codeUnit, string serviceName) 283 { 284 CodeDomProvider provider = GetProvider(); 285 ICodeGenerator generator = provider.CreateGenerator(); 286 CodeGeneratorOptions options = new CodeGeneratorOptions(); 287 288 string filename; 289 if (outFilename != null) 290 filename = outFilename; 291 else 292 filename = serviceName + "." + provider.FileExtension; 293 294 Console.WriteLine ("Writing file '{0}'", filename); 295 StreamWriter writer = new StreamWriter(filename); 296 generator.GenerateCodeFromCompileUnit(codeUnit, writer, options); 297 writer.Close(); 298 } 299 300 /// 301 /// <summary> 302 /// Fetch the Code Provider for the language specified by the 'language' members. 303 /// </summary> 304 /// GetProvider()305 private CodeDomProvider GetProvider() 306 { 307 CodeDomProvider provider; 308 Type type; 309 310 switch (language.ToUpper ()) { 311 case "CS": 312 provider = new CSharpCodeProvider (); 313 break; 314 case "VB": 315 provider = new Microsoft.VisualBasic.VBCodeProvider (); 316 break; 317 case "BOO": 318 type = Type.GetType("Boo.Lang.CodeDom.BooCodeProvider, Boo.Lang.CodeDom, Version=1.0.0.0, Culture=neutral, PublicKeyToken=32c39770e9a21a67"); 319 if (type != null){ 320 return (CodeDomProvider) Activator.CreateInstance (type); 321 } 322 throw new Exception ("Boo.Lang.CodeDom.BooCodeProvider not available"); 323 324 default: 325 type = Type.GetType(language); 326 if (type != null) { 327 return (CodeDomProvider) Activator.CreateInstance (type); 328 } 329 throw new Exception ("Unknown language"); 330 } 331 return provider; 332 } 333 334 335 336 /// 337 /// <summary> 338 /// Interperet the command-line arguments and configure the relavent components. 339 /// </summary> 340 /// ImportArgument(string argument)341 void ImportArgument(string argument) 342 { 343 string optionValuePair; 344 345 if (argument.StartsWith("--")) 346 { 347 optionValuePair = argument.Substring(2); 348 } 349 else if (argument.StartsWith("/") || argument.StartsWith("-")) 350 { 351 optionValuePair = argument.Substring(1); 352 } 353 else 354 { 355 urls.Add (argument); 356 return; 357 } 358 359 string option; 360 string value; 361 362 int indexOfEquals = optionValuePair.IndexOf(':'); 363 if (indexOfEquals > 0) 364 { 365 option = optionValuePair.Substring(0, indexOfEquals); 366 value = optionValuePair.Substring(indexOfEquals + 1); 367 } 368 else 369 { 370 option = optionValuePair; 371 value = null; 372 } 373 374 switch (option) 375 { 376 case "appsettingurlkey": 377 case "urlkey": 378 appSettingURLKey = value; 379 break; 380 381 case "appsettingbaseurl": 382 case "baseurl": 383 appSettingBaseURL = value; 384 break; 385 386 case "d": 387 case "domain": 388 domain = value; 389 break; 390 391 case "l": 392 case "language": 393 language = value; 394 break; 395 396 case "n": 397 case "namespace": 398 ns = value; 399 break; 400 401 case "nologo": 402 noLogo = true; 403 break; 404 405 case "o": 406 case "out": 407 outFilename = value; 408 break; 409 410 case "p": 411 case "password": 412 password = value; 413 break; 414 415 case "protocol": 416 protocol = value; 417 break; 418 419 case "proxy": 420 proxyAddress = value; 421 break; 422 423 case "proxydomain": 424 case "pd": 425 proxyDomain = value; 426 break; 427 428 case "proxypassword": 429 case "pp": 430 proxyPassword = value; 431 break; 432 433 case "proxyusername": 434 case "pu": 435 proxyUsername = value; 436 break; 437 438 case "server": 439 style = ServiceDescriptionImportStyle.Server; 440 break; 441 442 case "u": 443 case "username": 444 username = value; 445 break; 446 447 case "verbose": 448 verbose = true; 449 break; 450 451 case "fields": 452 options &= ~CodeGenerationOptions.GenerateProperties; 453 break; 454 455 case "sample": 456 sampleSoap = value; 457 break; 458 459 case "?": 460 help = true; 461 break; 462 463 default: 464 if (argument.StartsWith ("/") && argument.IndexOfAny (Path.InvalidPathChars) == -1) { 465 urls.Add (argument); 466 break; 467 } 468 else 469 throw new Exception("Unknown option " + option); 470 } 471 } 472 CreateClient()473 DiscoveryClientProtocol CreateClient () 474 { 475 DiscoveryClientProtocol dcc = new DiscoveryClientProtocol (); 476 477 if (username != null || password != null || domain != null) 478 { 479 NetworkCredential credentials = new NetworkCredential(); 480 481 if (username != null) 482 credentials.UserName = username; 483 484 if (password != null) 485 credentials.Password = password; 486 487 if (domain != null) 488 credentials.Domain = domain; 489 490 dcc.Credentials = credentials; 491 } 492 493 if (proxyAddress != null) 494 { 495 WebProxy proxy = new WebProxy (proxyAddress); 496 if (proxyUsername != null || proxyPassword != null || proxyDomain != null) 497 { 498 NetworkCredential credentials = new NetworkCredential(); 499 500 if (proxyUsername != null) 501 credentials.UserName = proxyUsername; 502 503 if (proxyPassword != null) 504 credentials.Password = proxyPassword; 505 506 if (proxyDomain != null) 507 credentials.Domain = proxyDomain; 508 509 proxy.Credentials = credentials; 510 } 511 } 512 513 return dcc; 514 } 515 WriteText(string text, int initialLeftMargin, int leftMargin)516 static void WriteText (string text, int initialLeftMargin, int leftMargin) 517 { 518 int n = 0; 519 int margin = initialLeftMargin; 520 int maxCols = 80; 521 522 if (text == "") { 523 Console.WriteLine (); 524 return; 525 } 526 527 while (n < text.Length) 528 { 529 int col = margin; 530 int lastWhite = -1; 531 int sn = n; 532 while (col < maxCols && n < text.Length) { 533 if (char.IsWhiteSpace (text[n])) 534 lastWhite = n; 535 col++; 536 n++; 537 } 538 539 if (lastWhite == -1 || col < maxCols) 540 lastWhite = n; 541 else if (col >= maxCols) 542 n = lastWhite + 1; 543 544 Console.WriteLine (new String (' ', margin) + text.Substring (sn, lastWhite - sn)); 545 margin = leftMargin; 546 } 547 } 548 } 549 } 550 551