1 //------------------------------------------------------------------------------ 2 // <copyright from='1997' to='2001' company='Microsoft Corporation'> 3 // Copyright (c) Microsoft Corporation. All Rights Reserved. 4 // Information Contained Herein is Proprietary and Confidential. 5 // </copyright> 6 //------------------------------------------------------------------------------ 7 namespace System.Web.Services.Description { 8 9 using System.Web.Services; 10 using System.Web.Services.Protocols; 11 using System.Xml; 12 using System.Xml.Serialization; 13 using System.Xml.Serialization.Advanced; 14 using System.Xml.Schema; 15 using System.Collections; 16 using System; 17 using System.Data; 18 using System.Data.Design; 19 using System.Reflection; 20 using System.CodeDom; 21 using System.CodeDom.Compiler; 22 using System.Web.Services.Configuration; 23 using System.Diagnostics; 24 using System.ComponentModel; 25 using System.Security.Permissions; 26 using System.Globalization; 27 using System.Threading; 28 29 internal class SoapParameters { 30 XmlMemberMapping ret; 31 ArrayList parameters = new ArrayList(); 32 ArrayList inParameters = new ArrayList(); 33 ArrayList outParameters = new ArrayList(); 34 int checkSpecifiedCount; 35 int inCheckSpecifiedCount; 36 int outCheckSpecifiedCount; 37 SoapParameters(XmlMembersMapping request, XmlMembersMapping response, string[] parameterOrder, CodeIdentifiers identifiers)38 internal SoapParameters(XmlMembersMapping request, XmlMembersMapping response, string[] parameterOrder, CodeIdentifiers identifiers) { 39 ArrayList requestList = new ArrayList(); 40 ArrayList responseList = new ArrayList(); 41 42 AddMappings(requestList, request); 43 if (response != null) AddMappings(responseList, response); 44 45 if (parameterOrder != null) { 46 for (int i = 0; i < parameterOrder.Length; i++) { 47 string elementName = parameterOrder[i]; 48 XmlMemberMapping requestMapping = FindMapping(requestList, elementName); 49 SoapParameter parameter = new SoapParameter(); 50 if (requestMapping != null) { 51 if (RemoveByRefMapping(responseList, requestMapping)) 52 parameter.codeFlags = CodeFlags.IsByRef; 53 parameter.mapping = requestMapping; 54 requestList.Remove(requestMapping); 55 AddParameter(parameter); 56 } 57 else { 58 XmlMemberMapping responseMapping = FindMapping(responseList, elementName); 59 if (responseMapping != null) { 60 parameter.codeFlags = CodeFlags.IsOut; 61 parameter.mapping = responseMapping; 62 responseList.Remove(responseMapping); 63 AddParameter(parameter); 64 } 65 } 66 } 67 } 68 69 foreach (XmlMemberMapping requestMapping in requestList) { 70 SoapParameter parameter = new SoapParameter(); 71 if (RemoveByRefMapping(responseList, requestMapping)) 72 parameter.codeFlags = CodeFlags.IsByRef; 73 parameter.mapping = requestMapping; 74 AddParameter(parameter); 75 } 76 77 if (responseList.Count > 0) { 78 if (!((XmlMemberMapping) responseList[0]).CheckSpecified) { 79 ret = (XmlMemberMapping)responseList[0]; 80 responseList.RemoveAt(0); 81 } 82 foreach (XmlMemberMapping responseMapping in responseList) { 83 SoapParameter parameter = new SoapParameter(); 84 parameter.mapping = responseMapping; 85 parameter.codeFlags = CodeFlags.IsOut; 86 AddParameter(parameter); 87 } 88 } 89 90 foreach (SoapParameter parameter in parameters) { 91 parameter.name = identifiers.MakeUnique(CodeIdentifier.MakeValid(parameter.mapping.MemberName)); 92 } 93 } 94 AddParameter(SoapParameter parameter)95 void AddParameter(SoapParameter parameter) { 96 parameters.Add(parameter); 97 if (parameter.mapping.CheckSpecified) { 98 checkSpecifiedCount++; 99 } 100 if (parameter.IsByRef) { 101 inParameters.Add(parameter); 102 outParameters.Add(parameter); 103 if (parameter.mapping.CheckSpecified) { 104 inCheckSpecifiedCount++; 105 outCheckSpecifiedCount++; 106 } 107 } else if (parameter.IsOut) { 108 outParameters.Add(parameter); 109 if (parameter.mapping.CheckSpecified) 110 outCheckSpecifiedCount++; 111 } 112 else { 113 inParameters.Add(parameter); 114 if (parameter.mapping.CheckSpecified) 115 inCheckSpecifiedCount++; 116 } 117 } 118 RemoveByRefMapping(ArrayList responseList, XmlMemberMapping requestMapping)119 static bool RemoveByRefMapping(ArrayList responseList, XmlMemberMapping requestMapping) { 120 XmlMemberMapping responseMapping = FindMapping(responseList, requestMapping.ElementName); 121 if (responseMapping == null) return false; 122 if (requestMapping.TypeFullName != responseMapping.TypeFullName) return false; 123 if (requestMapping.Namespace != responseMapping.Namespace) return false; 124 if (requestMapping.MemberName != responseMapping.MemberName) return false; 125 responseList.Remove(responseMapping); 126 return true; 127 } 128 AddMappings(ArrayList mappingsList, XmlMembersMapping mappings)129 static void AddMappings(ArrayList mappingsList, XmlMembersMapping mappings) { 130 for (int i = 0; i < mappings.Count; i++) { 131 mappingsList.Add(mappings[i]); 132 } 133 } 134 FindMapping(ArrayList mappingsList, string elementName)135 static XmlMemberMapping FindMapping(ArrayList mappingsList, string elementName) { 136 foreach (XmlMemberMapping mapping in mappingsList) 137 if (mapping.ElementName == elementName) 138 return mapping; 139 return null; 140 } 141 142 internal XmlMemberMapping Return { 143 get { return ret; } 144 } 145 146 internal IList Parameters { 147 get { return parameters; } 148 } 149 150 internal IList InParameters { 151 get { return inParameters; } 152 } 153 154 internal IList OutParameters { 155 get { return outParameters; } 156 } 157 158 internal int CheckSpecifiedCount { 159 get { return checkSpecifiedCount; } 160 } 161 162 internal int InCheckSpecifiedCount { 163 get { return inCheckSpecifiedCount; } 164 } 165 166 internal int OutCheckSpecifiedCount { 167 get { return outCheckSpecifiedCount; } 168 } 169 } 170 171 internal class SoapParameter { 172 internal CodeFlags codeFlags; 173 internal string name; 174 internal XmlMemberMapping mapping; 175 internal string specifiedName; 176 177 internal bool IsOut { 178 get { return (codeFlags & CodeFlags.IsOut) != 0; } 179 } 180 181 internal bool IsByRef { 182 get { return (codeFlags & CodeFlags.IsByRef) != 0; } 183 } 184 GetTypeFullNames(IList parameters, int specifiedCount, CodeDomProvider codeProvider)185 internal static string[] GetTypeFullNames(IList parameters, int specifiedCount, CodeDomProvider codeProvider) { 186 string[] typeFullNames = new string[parameters.Count + specifiedCount]; 187 GetTypeFullNames(parameters, typeFullNames, 0, specifiedCount, codeProvider); 188 return typeFullNames; 189 } 190 GetTypeFullNames(IList parameters, string[] typeFullNames, int start, int specifiedCount, CodeDomProvider codeProvider)191 internal static void GetTypeFullNames(IList parameters, string[] typeFullNames, int start, int specifiedCount, CodeDomProvider codeProvider) { 192 int specified = 0; 193 for (int i = 0; i < parameters.Count; i++) { 194 typeFullNames[i + start + specified] = WebCodeGenerator.FullTypeName(((SoapParameter)parameters[i]).mapping, codeProvider); 195 if (((SoapParameter) parameters[i]).mapping.CheckSpecified) { 196 specified++; 197 typeFullNames[i + start + specified] = typeof(bool).FullName; 198 } 199 } 200 } 201 GetNames(IList parameters, int specifiedCount)202 internal static string[] GetNames(IList parameters, int specifiedCount) { 203 string[] names = new string[parameters.Count + specifiedCount]; 204 GetNames(parameters, names, 0, specifiedCount); 205 return names; 206 } 207 GetNames(IList parameters, string[] names, int start, int specifiedCount)208 internal static void GetNames(IList parameters, string[] names, int start, int specifiedCount) { 209 int specified = 0; 210 for (int i = 0; i < parameters.Count; i++) { 211 names[i + start + specified] = ((SoapParameter)parameters[i]).name; 212 if (((SoapParameter) parameters[i]).mapping.CheckSpecified) { 213 specified++; 214 names[i + start + specified] = ((SoapParameter) parameters[i]).specifiedName; 215 } 216 } 217 } 218 GetCodeFlags(IList parameters, int specifiedCount)219 internal static CodeFlags[] GetCodeFlags(IList parameters, int specifiedCount) { 220 CodeFlags[] codeFlags = new CodeFlags[parameters.Count + specifiedCount]; 221 GetCodeFlags(parameters, codeFlags, 0, specifiedCount); 222 return codeFlags; 223 } 224 GetCodeFlags(IList parameters, CodeFlags[] codeFlags, int start, int specifiedCount)225 internal static void GetCodeFlags(IList parameters, CodeFlags[] codeFlags, int start, int specifiedCount) { 226 int specified = 0; 227 for (int i = 0; i < parameters.Count; i++) { 228 codeFlags[i + start + specified] = ((SoapParameter)parameters[i]).codeFlags; 229 if (((SoapParameter) parameters[i]).mapping.CheckSpecified) { 230 specified++; 231 codeFlags[i + start + specified] = ((SoapParameter) parameters[i]).codeFlags; 232 } 233 } 234 } 235 } 236 237 internal class GlobalSoapHeader { 238 internal string fieldName; 239 internal XmlTypeMapping mapping; 240 internal bool isEncoded; 241 } 242 243 internal class LocalSoapHeader { 244 internal SoapHeaderDirection direction; 245 internal string fieldName; 246 } 247 248 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter"]/*' /> 249 /// <devdoc> 250 /// <para>[To be supplied.]</para> 251 /// </devdoc> 252 [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")] 253 [PermissionSet(SecurityAction.InheritanceDemand, Name = "FullTrust")] 254 public class SoapProtocolImporter : ProtocolImporter { 255 XmlSchemaImporter xmlImporter; 256 XmlCodeExporter xmlExporter; 257 SoapSchemaImporter soapImporter; 258 SoapCodeExporter soapExporter; 259 ArrayList xmlMembers = new ArrayList(); 260 ArrayList soapMembers = new ArrayList(); 261 Hashtable headers = new Hashtable(); 262 Hashtable classHeaders = new Hashtable(); 263 ArrayList propertyNames = new ArrayList(); 264 ArrayList propertyValues = new ArrayList(); 265 SoapExtensionImporter[] extensions; 266 SoapTransportImporter transport; 267 SoapBinding soapBinding; 268 ArrayList codeClasses = new ArrayList(); 269 static TypedDataSetSchemaImporterExtension typedDataSetSchemaImporterExtension; 270 271 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.ProtocolName"]/*' /> 272 /// <devdoc> 273 /// <para>[To be supplied.]</para> 274 /// </devdoc> 275 public override string ProtocolName { 276 get { return "Soap"; } 277 } 278 279 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.SoapBinding"]/*' /> 280 /// <devdoc> 281 /// <para>[To be supplied.]</para> 282 /// </devdoc> 283 public SoapBinding SoapBinding { 284 get { return soapBinding; } 285 } 286 287 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.SoapImporter"]/*' /> 288 /// <devdoc> 289 /// <para>[To be supplied.]</para> 290 /// </devdoc> 291 public SoapSchemaImporter SoapImporter { 292 get { return soapImporter; } 293 } 294 295 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.XmlImporter"]/*' /> 296 /// <devdoc> 297 /// <para>[To be supplied.]</para> 298 /// </devdoc> 299 public XmlSchemaImporter XmlImporter { 300 get { return xmlImporter; } 301 } 302 303 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.XmlExporter"]/*' /> 304 /// <devdoc> 305 /// <para>[To be supplied.]</para> 306 /// </devdoc> 307 public XmlCodeExporter XmlExporter { 308 get { return xmlExporter; } 309 } 310 311 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.SoapExporter"]/*' /> 312 /// <devdoc> 313 /// <para>[To be supplied.]</para> 314 /// </devdoc> 315 public SoapCodeExporter SoapExporter { 316 get { return soapExporter; } 317 } 318 319 static TypedDataSetSchemaImporterExtension TypedDataSetSchemaImporterExtension { 320 get { 321 if (typedDataSetSchemaImporterExtension == null) { 322 typedDataSetSchemaImporterExtension = new TypedDataSetSchemaImporterExtension(); 323 } 324 return typedDataSetSchemaImporterExtension; 325 } 326 } 327 328 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.BeginNamespace"]/*' /> 329 /// <devdoc> 330 /// <para>[To be supplied.]</para> 331 /// </devdoc> BeginNamespace()332 protected override void BeginNamespace() { 333 try { 334 MethodNames.Clear(); 335 ExtraCodeClasses.Clear(); 336 soapImporter = new SoapSchemaImporter(AbstractSchemas, ServiceImporter.CodeGenerationOptions, ImportContext); 337 xmlImporter = new XmlSchemaImporter(ConcreteSchemas, ServiceImporter.CodeGenerationOptions, ServiceImporter.CodeGenerator, ImportContext); 338 foreach (Type extensionType in ServiceImporter.Extensions) { 339 xmlImporter.Extensions.Add(extensionType.FullName, extensionType); 340 } 341 // use cached version of typed DataSetSchemaImporterExtension for /sharetypes feature 342 // 343 xmlImporter.Extensions.Add(TypedDataSetSchemaImporterExtension); 344 xmlImporter.Extensions.Add(new DataSetSchemaImporterExtension()); 345 xmlExporter = new XmlCodeExporter(this.CodeNamespace, ServiceImporter.CodeCompileUnit, ServiceImporter.CodeGenerator, ServiceImporter.CodeGenerationOptions, ExportContext); 346 soapExporter = new SoapCodeExporter(this.CodeNamespace, null, ServiceImporter.CodeGenerator, ServiceImporter.CodeGenerationOptions, ExportContext); 347 } 348 catch (Exception e) { 349 if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) { 350 throw; 351 } 352 throw new InvalidOperationException(Res.GetString(Res.InitFailed), e); 353 } 354 } 355 356 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.EndNamespace"]/*' /> 357 /// <devdoc> 358 /// <para>[To be supplied.]</para> 359 /// </devdoc> EndNamespace()360 protected override void EndNamespace() { 361 // need to preprocess all exported schemas to make sure that IXmlSerializable schemas are Merged and the resulting set is valid 362 ConcreteSchemas.Compile(null, false); 363 364 foreach (GlobalSoapHeader soapHeader in headers.Values) { 365 if (soapHeader.isEncoded) 366 soapExporter.ExportTypeMapping(soapHeader.mapping); 367 else 368 xmlExporter.ExportTypeMapping(soapHeader.mapping); 369 } 370 371 foreach (XmlMembersMapping member in xmlMembers) 372 xmlExporter.ExportMembersMapping(member); 373 374 foreach (XmlMembersMapping member in soapMembers) 375 soapExporter.ExportMembersMapping(member); 376 377 // NOTE, Microsoft, we are sharing the SoapInclude and XmlInclude attributes of the 378 // class among ALL classes generated, This is probably OK, since doing to per 379 // class would probably result in the same set of includes if the user 380 // has object as a return value (meaning 'all' types are OK). 381 foreach (CodeTypeDeclaration codeClass in codeClasses) { 382 foreach (CodeAttributeDeclaration attribute in xmlExporter.IncludeMetadata) { 383 codeClass.CustomAttributes.Add(attribute); 384 } 385 foreach (CodeAttributeDeclaration attribute in soapExporter.IncludeMetadata) { 386 codeClass.CustomAttributes.Add(attribute); 387 } 388 } 389 foreach (CodeTypeDeclaration declaration in ExtraCodeClasses) { 390 this.CodeNamespace.Types.Add(declaration); 391 } 392 CodeGenerator.ValidateIdentifiers(CodeNamespace); 393 } 394 395 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.IsBindingSupported"]/*' /> 396 /// <devdoc> 397 /// <para>[To be supplied.]</para> 398 /// </devdoc> IsBindingSupported()399 protected override bool IsBindingSupported() { 400 SoapBinding soapBinding = (SoapBinding)Binding.Extensions.Find(typeof(SoapBinding)); 401 if (soapBinding == null || soapBinding.GetType() != typeof(SoapBinding)) return false; 402 403 if (GetTransport(soapBinding.Transport) == null) { 404 UnsupportedBindingWarning(Res.GetString(Res.ThereIsNoSoapTransportImporterThatUnderstands1, soapBinding.Transport)); 405 return false; 406 } 407 408 return true; 409 } 410 GetTransport(string transport)411 internal SoapTransportImporter GetTransport(string transport) { 412 foreach (Type type in WebServicesSection.Current.SoapTransportImporters) 413 { 414 SoapTransportImporter transportImporter = (SoapTransportImporter)Activator.CreateInstance(type); 415 transportImporter.ImportContext = this; 416 if (transportImporter.IsSupportedTransport(transport)) return transportImporter; 417 } 418 return null; 419 } 420 421 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.BeginClass"]/*' /> 422 /// <devdoc> 423 /// <para>[To be supplied.]</para> 424 /// </devdoc> BeginClass()425 protected override CodeTypeDeclaration BeginClass() { 426 MethodNames.Clear(); 427 428 soapBinding = (SoapBinding)Binding.Extensions.Find(typeof(SoapBinding)); 429 transport = GetTransport(soapBinding.Transport); 430 431 Type[] requiredTypes = new Type[] { typeof(SoapDocumentMethodAttribute), typeof(XmlAttributeAttribute), typeof(WebService), typeof(Object), typeof(DebuggerStepThroughAttribute), typeof(DesignerCategoryAttribute) }; 432 WebCodeGenerator.AddImports(this.CodeNamespace, WebCodeGenerator.GetNamespacesForTypes(requiredTypes)); 433 CodeFlags flags = 0; 434 if (Style == ServiceDescriptionImportStyle.Server) 435 flags = CodeFlags.IsAbstract; 436 else if (Style == ServiceDescriptionImportStyle.ServerInterface) 437 flags = CodeFlags.IsInterface; 438 CodeTypeDeclaration codeClass = WebCodeGenerator.CreateClass(this.ClassName, null, 439 new string[0], null, CodeFlags.IsPublic | flags, 440 ServiceImporter.CodeGenerator.Supports(GeneratorSupport.PartialTypes)); 441 442 codeClass.Comments.Add(new CodeCommentStatement(Res.GetString(Res.CodeRemarks), true)); 443 if (Style == ServiceDescriptionImportStyle.Client) { 444 codeClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(DebuggerStepThroughAttribute).FullName)); 445 codeClass.CustomAttributes.Add(new CodeAttributeDeclaration(typeof(DesignerCategoryAttribute).FullName, new CodeAttributeArgument[] { new CodeAttributeArgument(new CodePrimitiveExpression("code")) })); 446 } 447 else if (Style == ServiceDescriptionImportStyle.Server) { 448 CodeAttributeDeclaration webService = new CodeAttributeDeclaration(typeof(WebServiceAttribute).FullName); 449 string targetNs = Service != null ? Service.ServiceDescription.TargetNamespace : Binding.ServiceDescription.TargetNamespace; 450 webService.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(targetNs))); 451 codeClass.CustomAttributes.Add(webService); 452 } 453 454 CodeAttributeDeclaration attribute = new CodeAttributeDeclaration(typeof(WebServiceBindingAttribute).FullName); 455 attribute.Arguments.Add(new CodeAttributeArgument("Name", new CodePrimitiveExpression(XmlConvert.DecodeName(Binding.Name)))); 456 attribute.Arguments.Add(new CodeAttributeArgument("Namespace", new CodePrimitiveExpression(Binding.ServiceDescription.TargetNamespace))); 457 458 codeClass.CustomAttributes.Add(attribute); 459 460 codeClasses.Add(codeClass); 461 classHeaders.Clear(); 462 return codeClass; 463 } 464 465 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.EndClass"]/*' /> 466 /// <devdoc> 467 /// <para>[To be supplied.]</para> 468 /// </devdoc> EndClass()469 protected override void EndClass() { 470 if (transport != null) 471 transport.ImportClass(); 472 soapBinding = null; 473 } 474 475 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.IsOperationFlowSupported"]/*' /> 476 /// <devdoc> 477 /// <para>[To be supplied.]</para> 478 /// </devdoc> IsOperationFlowSupported(OperationFlow flow)479 protected override bool IsOperationFlowSupported(OperationFlow flow) { 480 return flow == OperationFlow.OneWay || flow == OperationFlow.RequestResponse; 481 } 482 BeginMetadata()483 void BeginMetadata() { 484 propertyNames.Clear(); 485 propertyValues.Clear(); 486 } 487 488 bool MetadataPropertiesAdded { 489 get { return propertyNames.Count > 0; } 490 } 491 AddMetadataProperty(string name, object value)492 void AddMetadataProperty(string name, object value) { 493 AddMetadataProperty(name, new CodePrimitiveExpression(value)); 494 } 495 AddMetadataProperty(string name, CodeExpression expr)496 void AddMetadataProperty(string name, CodeExpression expr) { 497 propertyNames.Add(name); 498 propertyValues.Add(expr); 499 } 500 EndMetadata(CodeAttributeDeclarationCollection metadata, Type attributeType, string parameter)501 void EndMetadata(CodeAttributeDeclarationCollection metadata, Type attributeType, string parameter) { 502 CodeExpression[] parameters; 503 if (parameter == null) { 504 parameters = new CodeExpression[0]; 505 } 506 else { 507 parameters = new CodeExpression[1] { new CodePrimitiveExpression(parameter) }; 508 } 509 WebCodeGenerator.AddCustomAttribute(metadata, attributeType, parameters, 510 (string[])propertyNames.ToArray(typeof(string)), 511 (CodeExpression[])propertyValues.ToArray(typeof(CodeExpression))); 512 } 513 GenerateExtensionMetadata(CodeAttributeDeclarationCollection metadata)514 void GenerateExtensionMetadata(CodeAttributeDeclarationCollection metadata) { 515 if (extensions == null) { 516 TypeElementCollection extensionTypes = WebServicesSection.Current.SoapExtensionImporterTypes; 517 extensions = new SoapExtensionImporter[extensionTypes.Count]; 518 for (int i = 0; i < extensions.Length; i++) { 519 SoapExtensionImporter extension = (SoapExtensionImporter)Activator.CreateInstance(extensionTypes[i].Type); 520 extension.ImportContext = this; 521 extensions[i] = extension; 522 } 523 } 524 foreach (SoapExtensionImporter extension in extensions) { 525 extension.ImportMethod(metadata); 526 } 527 } 528 PrepareHeaders(MessageBinding messageBinding)529 void PrepareHeaders(MessageBinding messageBinding) { 530 // By default, map all headers to properties on the generated class 531 // ExtensionImporters can modify this behavior by clearing the flag 532 SoapHeaderBinding[] headers = (SoapHeaderBinding[])messageBinding.Extensions.FindAll(typeof(SoapHeaderBinding)); 533 foreach (SoapHeaderBinding header in headers) { 534 header.MapToProperty = true; 535 } 536 } 537 GenerateHeaders(CodeAttributeDeclarationCollection metadata, SoapBindingUse use, bool rpc, MessageBinding requestMessage, MessageBinding responseMessage)538 void GenerateHeaders(CodeAttributeDeclarationCollection metadata, SoapBindingUse use, bool rpc, MessageBinding requestMessage, MessageBinding responseMessage) { 539 Hashtable localHeaders = new Hashtable(); 540 541 for (int i = 0; i < 2; ++i) { 542 MessageBinding messageBinding; 543 SoapHeaderDirection direction; 544 if (i == 0) { 545 messageBinding = requestMessage; 546 direction = SoapHeaderDirection.In; 547 } 548 else if (responseMessage != null) { 549 messageBinding = responseMessage; 550 direction = SoapHeaderDirection.Out; 551 } 552 else 553 continue; 554 555 SoapHeaderBinding[] headerBindings = (SoapHeaderBinding[])messageBinding.Extensions.FindAll(typeof(SoapHeaderBinding)); 556 foreach (SoapHeaderBinding header in headerBindings) { 557 // Skip headers which should not be mapped to properties (extension importers can control this) 558 if (!header.MapToProperty) continue; 559 560 if (use != header.Use) throw new InvalidOperationException(Res.GetString(Res.WebDescriptionHeaderAndBodyUseMismatch)); 561 if (use == SoapBindingUse.Encoded && !IsSoapEncodingPresent(header.Encoding) ) 562 throw new InvalidOperationException(Res.GetString(Res.WebUnknownEncodingStyle, header.Encoding)); 563 564 Message message = ServiceDescriptions.GetMessage(header.Message); 565 if (message == null) throw new InvalidOperationException(Res.GetString(Res.MissingMessage2, header.Message.Name, header.Message.Namespace)); 566 567 MessagePart part = message.FindPartByName(header.Part); 568 if (part == null) throw new InvalidOperationException(Res.GetString(Res.MissingMessagePartForMessageFromNamespace3, part.Name, header.Message.Name, header.Message.Namespace)); 569 570 XmlTypeMapping mapping; 571 string key; 572 if (use == SoapBindingUse.Encoded) { 573 if (part.Type.IsEmpty) throw new InvalidOperationException(Res.GetString(Res.WebDescriptionPartTypeRequired, part.Name, header.Message.Name, header.Message.Namespace)); 574 if (!part.Element.IsEmpty) UnsupportedOperationBindingWarning(Res.GetString(Res.WebDescriptionPartElementWarning, part.Name, header.Message.Name, header.Message.Namespace)); 575 mapping = soapImporter.ImportDerivedTypeMapping(part.Type, typeof(SoapHeader), true); 576 key = "type=" + part.Type.ToString(); 577 } 578 else { 579 if (part.Element.IsEmpty) throw new InvalidOperationException(Res.GetString(Res.WebDescriptionPartElementRequired, part.Name, header.Message.Name, header.Message.Namespace)); 580 if (!part.Type.IsEmpty) UnsupportedOperationBindingWarning(Res.GetString(Res.WebDescriptionPartTypeWarning, part.Name, header.Message.Name, header.Message.Namespace)); 581 mapping = xmlImporter.ImportDerivedTypeMapping(part.Element, typeof(SoapHeader), true); 582 key = "element=" + part.Element.ToString(); 583 } 584 LocalSoapHeader localHeader = (LocalSoapHeader)localHeaders[key]; 585 if (localHeader == null) { 586 GlobalSoapHeader globalHeader = (GlobalSoapHeader)classHeaders[key]; 587 if (globalHeader == null) { 588 globalHeader = new GlobalSoapHeader(); 589 globalHeader.isEncoded = use == SoapBindingUse.Encoded; 590 string fieldName = CodeIdentifier.MakeValid(mapping.ElementName); 591 if (fieldName == mapping.TypeName) fieldName += "Value"; 592 fieldName = MethodNames.AddUnique(fieldName, mapping); 593 globalHeader.fieldName = fieldName; 594 WebCodeGenerator.AddMember(CodeTypeDeclaration, mapping.TypeFullName, globalHeader.fieldName, null, null, CodeFlags.IsPublic, ServiceImporter.CodeGenerationOptions); 595 globalHeader.mapping = mapping; 596 classHeaders.Add(key, globalHeader); 597 if (headers[key] == null) 598 headers.Add(key, globalHeader); 599 } 600 601 localHeader = new LocalSoapHeader(); 602 localHeader.fieldName = globalHeader.fieldName; 603 localHeader.direction = direction; 604 localHeaders.Add(key, localHeader); 605 } 606 else { 607 if (localHeader.direction != direction) 608 localHeader.direction = SoapHeaderDirection.InOut; 609 } 610 } 611 } 612 613 foreach (LocalSoapHeader soapHeader in localHeaders.Values) { 614 BeginMetadata(); 615 if (soapHeader.direction == SoapHeaderDirection.Out) { 616 AddMetadataProperty("Direction", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(SoapHeaderDirection).FullName), SoapHeaderDirection.Out.ToString())); 617 } 618 else if (soapHeader.direction == SoapHeaderDirection.InOut) { 619 AddMetadataProperty("Direction", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(SoapHeaderDirection).FullName), SoapHeaderDirection.InOut.ToString())); 620 } 621 622 EndMetadata(metadata, typeof(SoapHeaderAttribute), soapHeader.fieldName); 623 } 624 } 625 626 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.GenerateMethod"]/*' /> 627 /// <devdoc> 628 /// <para>[To be supplied.]</para> 629 /// </devdoc> GenerateMethod()630 protected override CodeMemberMethod GenerateMethod() { 631 Message requestMessage; 632 Message responseMessage; 633 string[] parameterOrder; 634 SoapBodyBinding soapRequestBinding; 635 SoapBodyBinding soapResponseBinding; 636 MessageBinding requestBinding; 637 MessageBinding responseBinding; 638 639 SoapOperationBinding soapOperationBinding = (SoapOperationBinding)this.OperationBinding.Extensions.Find(typeof(SoapOperationBinding)); 640 if (soapOperationBinding == null) throw OperationBindingSyntaxException(Res.GetString(Res.MissingSoapOperationBinding0)); 641 642 SoapBindingStyle soapBindingStyle = soapOperationBinding.Style; 643 if (soapBindingStyle == SoapBindingStyle.Default) 644 soapBindingStyle = SoapBinding.Style; 645 if (soapBindingStyle == SoapBindingStyle.Default) 646 soapBindingStyle = SoapBindingStyle.Document; 647 648 parameterOrder = this.Operation.ParameterOrder; 649 650 requestMessage = this.InputMessage; 651 requestBinding = this.OperationBinding.Input; 652 soapRequestBinding = (SoapBodyBinding)this.OperationBinding.Input.Extensions.Find(typeof(SoapBodyBinding)); 653 if (soapRequestBinding == null) { 654 UnsupportedOperationBindingWarning(Res.GetString(Res.MissingSoapBodyInputBinding0)); 655 return null; 656 } 657 658 if (this.Operation.Messages.Output != null) { 659 responseMessage = this.OutputMessage; 660 responseBinding = this.OperationBinding.Output; 661 soapResponseBinding = (SoapBodyBinding)this.OperationBinding.Output.Extensions.Find(typeof(SoapBodyBinding)); 662 if (soapResponseBinding == null) { 663 UnsupportedOperationBindingWarning(Res.GetString(Res.MissingSoapBodyOutputBinding0)); 664 return null; 665 } 666 } 667 else { 668 responseMessage = null; 669 responseBinding = null; 670 soapResponseBinding = null; 671 } 672 673 CodeAttributeDeclarationCollection metadata = new CodeAttributeDeclarationCollection(); 674 675 PrepareHeaders(requestBinding); 676 if (responseBinding != null) PrepareHeaders(responseBinding); 677 678 string requestMessageName; 679 string responseMessageName = null; 680 681 requestMessageName = !String.IsNullOrEmpty(requestBinding.Name) && soapBindingStyle != SoapBindingStyle.Rpc ? requestBinding.Name : this.Operation.Name; // per WSDL 1.1 sec 3.5 682 requestMessageName = XmlConvert.DecodeName(requestMessageName); 683 684 if (responseBinding != null) { 685 responseMessageName = !String.IsNullOrEmpty(responseBinding.Name) && soapBindingStyle != SoapBindingStyle.Rpc ? responseBinding.Name : this.Operation.Name + "Response"; // per WSDL 1.1 sec 3.5 686 responseMessageName = XmlConvert.DecodeName(responseMessageName); 687 } 688 689 GenerateExtensionMetadata(metadata); 690 GenerateHeaders(metadata, soapRequestBinding.Use, soapBindingStyle == SoapBindingStyle.Rpc, requestBinding, responseBinding); 691 692 MessagePart[] requestParts = GetMessageParts(requestMessage, soapRequestBinding); 693 bool hasWrapper; 694 if (!CheckMessageStyles(MethodName, requestParts, soapRequestBinding, soapBindingStyle, out hasWrapper)) 695 return null; 696 697 MessagePart[] responseParts = null; 698 if (responseMessage != null) { 699 responseParts = GetMessageParts(responseMessage, soapResponseBinding); 700 bool responseHasWrapper; 701 if (!CheckMessageStyles(MethodName, responseParts, soapResponseBinding, soapBindingStyle, out responseHasWrapper)) 702 return null; 703 704 // since we're using a potentially inaccurate heuristic to determine whether there's a wrapper, 705 // if we disagree about the request and response we should assume there isn't a wrapper. 706 if (hasWrapper != responseHasWrapper) 707 hasWrapper = false; 708 } 709 710 bool wrapperNamesMatter = (soapBindingStyle != SoapBindingStyle.Rpc && hasWrapper) || (soapRequestBinding.Use == SoapBindingUse.Literal && soapBindingStyle == SoapBindingStyle.Rpc); 711 712 XmlMembersMapping request = ImportMessage(requestMessageName, requestParts, soapRequestBinding, soapBindingStyle, hasWrapper); 713 if (request == null) return null; 714 715 XmlMembersMapping response = null; 716 717 if (responseMessage != null) { 718 response = ImportMessage(responseMessageName, responseParts, soapResponseBinding, soapBindingStyle, hasWrapper); 719 if (response == null) return null; 720 } 721 722 string methodName = CodeIdentifier.MakeValid(XmlConvert.DecodeName(this.Operation.Name)); 723 if (ClassName == methodName) { 724 methodName = "Call" + methodName; 725 } 726 string uniqueMethodName = MethodNames.AddUnique(CodeIdentifier.MakeValid(XmlConvert.DecodeName(methodName)), this.Operation); 727 bool differentNames = methodName != uniqueMethodName; 728 729 CodeIdentifiers localIdentifiers = new CodeIdentifiers(false); 730 localIdentifiers.AddReserved(uniqueMethodName); 731 732 SoapParameters parameters = new SoapParameters(request, response, parameterOrder, MethodNames); 733 734 foreach (SoapParameter param in parameters.Parameters) { 735 if ((param.IsOut || param.IsByRef) && !ServiceImporter.CodeGenerator.Supports(GeneratorSupport.ReferenceParameters)) { 736 UnsupportedOperationWarning(Res.GetString(Res.CodeGenSupportReferenceParameters, ServiceImporter.CodeGenerator.GetType().Name)); 737 return null; 738 } 739 param.name = localIdentifiers.AddUnique(param.name, null); 740 if (param.mapping.CheckSpecified) 741 param.specifiedName = localIdentifiers.AddUnique(param.name + "Specified", null); 742 } 743 744 if (!(Style == ServiceDescriptionImportStyle.Client) || differentNames) { 745 BeginMetadata(); 746 if (differentNames) AddMetadataProperty("MessageName", uniqueMethodName); 747 EndMetadata(metadata, typeof(WebMethodAttribute), null); 748 } 749 750 BeginMetadata(); 751 if (wrapperNamesMatter && request.ElementName.Length > 0 && request.ElementName != uniqueMethodName) 752 AddMetadataProperty("RequestElementName", request.ElementName); 753 if (request.Namespace != null) 754 AddMetadataProperty("RequestNamespace", request.Namespace); 755 if (response == null) { 756 AddMetadataProperty("OneWay", true); 757 } 758 else { 759 if (wrapperNamesMatter && response.ElementName.Length > 0 && response.ElementName != (uniqueMethodName + "Response")) 760 AddMetadataProperty("ResponseElementName", response.ElementName); 761 if (response.Namespace != null) 762 AddMetadataProperty("ResponseNamespace", response.Namespace); 763 } 764 765 if (soapBindingStyle == SoapBindingStyle.Rpc) { 766 if (soapRequestBinding.Use != SoapBindingUse.Encoded) { 767 AddMetadataProperty("Use", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(SoapBindingUse).FullName), Enum.Format(typeof(SoapBindingUse), soapRequestBinding.Use, "G"))); 768 } 769 EndMetadata(metadata, typeof(SoapRpcMethodAttribute), soapOperationBinding.SoapAction); 770 } 771 else { 772 AddMetadataProperty("Use", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(SoapBindingUse).FullName), Enum.Format(typeof(SoapBindingUse), soapRequestBinding.Use, "G"))); 773 AddMetadataProperty("ParameterStyle", new CodeFieldReferenceExpression(new CodeTypeReferenceExpression(typeof(SoapParameterStyle).FullName), Enum.Format(typeof(SoapParameterStyle), hasWrapper ? SoapParameterStyle.Wrapped : SoapParameterStyle.Bare, "G"))); 774 EndMetadata(metadata, typeof(SoapDocumentMethodAttribute), soapOperationBinding.SoapAction); 775 } 776 IsEncodedBinding = IsEncodedBinding || (soapRequestBinding.Use == SoapBindingUse.Encoded); 777 778 CodeAttributeDeclarationCollection[] paramsMetadata = new CodeAttributeDeclarationCollection[parameters.Parameters.Count + parameters.CheckSpecifiedCount]; 779 int j = 0; 780 CodeAttributeDeclaration ignoreAttribute = new CodeAttributeDeclaration(typeof(XmlIgnoreAttribute).FullName); 781 foreach (SoapParameter parameter in parameters.Parameters) { 782 paramsMetadata[j] = new CodeAttributeDeclarationCollection(); 783 if (soapRequestBinding.Use == SoapBindingUse.Encoded) 784 soapExporter.AddMappingMetadata(paramsMetadata[j], parameter.mapping, parameter.name != parameter.mapping.MemberName); 785 else { 786 string ns = soapBindingStyle == SoapBindingStyle.Rpc ? parameter.mapping.Namespace : parameter.IsOut ? response.Namespace : request.Namespace; 787 bool forceUseMemberName = parameter.name != parameter.mapping.MemberName; 788 xmlExporter.AddMappingMetadata(paramsMetadata[j], parameter.mapping, ns, forceUseMemberName); 789 if (parameter.mapping.CheckSpecified) { 790 j++; 791 paramsMetadata[j] = new CodeAttributeDeclarationCollection(); 792 xmlExporter.AddMappingMetadata(paramsMetadata[j], parameter.mapping, ns, parameter.specifiedName != parameter.mapping.MemberName + "Specified"); 793 paramsMetadata[j].Add(ignoreAttribute); 794 } 795 } 796 if (paramsMetadata[j].Count > 0 && !ServiceImporter.CodeGenerator.Supports(GeneratorSupport.ParameterAttributes)) { 797 UnsupportedOperationWarning(Res.GetString(Res.CodeGenSupportParameterAttributes, ServiceImporter.CodeGenerator.GetType().Name)); 798 return null; 799 } 800 j++; 801 } 802 803 CodeFlags[] parameterFlags = SoapParameter.GetCodeFlags(parameters.Parameters, parameters.CheckSpecifiedCount); 804 string[] parameterTypes = SoapParameter.GetTypeFullNames(parameters.Parameters, parameters.CheckSpecifiedCount, ServiceImporter.CodeGenerator); 805 string returnType = parameters.Return == null ? typeof(void).FullName : WebCodeGenerator.FullTypeName(parameters.Return, ServiceImporter.CodeGenerator); 806 807 CodeMemberMethod mainCodeMethod = WebCodeGenerator.AddMethod(this.CodeTypeDeclaration, methodName, 808 parameterFlags, 809 parameterTypes, 810 SoapParameter.GetNames(parameters.Parameters, parameters.CheckSpecifiedCount), 811 paramsMetadata, 812 returnType, 813 metadata, 814 CodeFlags.IsPublic | (Style == ServiceDescriptionImportStyle.Client ? 0 : CodeFlags.IsAbstract)); 815 816 mainCodeMethod.Comments.Add(new CodeCommentStatement(Res.GetString(Res.CodeRemarks), true)); 817 818 if (parameters.Return != null) { 819 if (soapRequestBinding.Use == SoapBindingUse.Encoded) 820 soapExporter.AddMappingMetadata(mainCodeMethod.ReturnTypeCustomAttributes, parameters.Return, parameters.Return.ElementName != uniqueMethodName + "Result"); 821 else 822 xmlExporter.AddMappingMetadata(mainCodeMethod.ReturnTypeCustomAttributes, parameters.Return, response.Namespace, parameters.Return.ElementName != uniqueMethodName + "Result"); 823 824 if (mainCodeMethod.ReturnTypeCustomAttributes.Count != 0 && !ServiceImporter.CodeGenerator.Supports(GeneratorSupport.ReturnTypeAttributes)) { 825 UnsupportedOperationWarning(Res.GetString(Res.CodeGenSupportReturnTypeAttributes, ServiceImporter.CodeGenerator.GetType().Name)); 826 return null; 827 } 828 } 829 830 string resultsName = localIdentifiers.MakeUnique("results"); 831 832 if (Style == ServiceDescriptionImportStyle.Client) { 833 bool oldAsync = (ServiceImporter.CodeGenerationOptions & CodeGenerationOptions.GenerateOldAsync) != 0; 834 bool newAsync = (ServiceImporter.CodeGenerationOptions & CodeGenerationOptions.GenerateNewAsync) != 0 && 835 ServiceImporter.CodeGenerator.Supports(GeneratorSupport.DeclareEvents) && 836 ServiceImporter.CodeGenerator.Supports(GeneratorSupport.DeclareDelegates); 837 CodeExpression[] invokeParams = new CodeExpression[2]; 838 CreateInvokeParams(invokeParams, uniqueMethodName, parameters.InParameters, parameters.InCheckSpecifiedCount); 839 CodeMethodInvokeExpression invoke = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "Invoke", invokeParams); 840 WriteReturnMappings(mainCodeMethod, invoke, parameters, resultsName); 841 842 if (oldAsync) { 843 int inCount = parameters.InParameters.Count + parameters.InCheckSpecifiedCount; 844 845 string[] asyncParameterTypes = new string[inCount + 2]; 846 SoapParameter.GetTypeFullNames(parameters.InParameters, asyncParameterTypes, 0, parameters.InCheckSpecifiedCount, ServiceImporter.CodeGenerator); 847 asyncParameterTypes[inCount] = typeof(AsyncCallback).FullName; 848 asyncParameterTypes[inCount + 1] = typeof(object).FullName; 849 850 string[] asyncParameterNames = new string[inCount + 2]; 851 SoapParameter.GetNames(parameters.InParameters, asyncParameterNames, 0, parameters.InCheckSpecifiedCount); 852 asyncParameterNames[inCount] = "callback"; 853 asyncParameterNames[inCount + 1] = "asyncState"; 854 855 CodeFlags[] asyncParameterFlags = new CodeFlags[inCount + 2]; 856 857 CodeMemberMethod beginCodeMethod = WebCodeGenerator.AddMethod(this.CodeTypeDeclaration, "Begin" + uniqueMethodName, 858 asyncParameterFlags, 859 asyncParameterTypes, 860 asyncParameterNames, 861 typeof(IAsyncResult).FullName, 862 null, 863 CodeFlags.IsPublic); 864 865 beginCodeMethod.Comments.Add(new CodeCommentStatement(Res.GetString(Res.CodeRemarks), true)); 866 867 invokeParams = new CodeExpression[4]; 868 CreateInvokeParams(invokeParams, uniqueMethodName, parameters.InParameters, parameters.InCheckSpecifiedCount); 869 invokeParams[2] = new CodeArgumentReferenceExpression("callback"); 870 invokeParams[3] = new CodeArgumentReferenceExpression("asyncState"); 871 872 invoke = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "BeginInvoke", invokeParams); 873 beginCodeMethod.Statements.Add(new CodeMethodReturnStatement(invoke)); 874 875 int outCount = parameters.OutParameters.Count + parameters.OutCheckSpecifiedCount; 876 string[] asyncReturnTypes = new string[outCount + 1]; 877 SoapParameter.GetTypeFullNames(parameters.OutParameters, asyncReturnTypes, 1, parameters.OutCheckSpecifiedCount, ServiceImporter.CodeGenerator); 878 asyncReturnTypes[0] = typeof(IAsyncResult).FullName; 879 880 string[] asyncReturnNames = new string[outCount + 1]; 881 SoapParameter.GetNames(parameters.OutParameters, asyncReturnNames, 1, parameters.OutCheckSpecifiedCount); 882 asyncReturnNames[0] = "asyncResult"; 883 884 CodeFlags[] asyncReturnFlags = new CodeFlags[outCount + 1]; 885 for (int i = 0; i < outCount; i++) 886 asyncReturnFlags[i + 1] = CodeFlags.IsOut; 887 888 CodeMemberMethod codeMethod = WebCodeGenerator.AddMethod(this.CodeTypeDeclaration, "End" + uniqueMethodName, 889 asyncReturnFlags, 890 asyncReturnTypes, 891 asyncReturnNames, 892 parameters.Return == null ? typeof(void).FullName : WebCodeGenerator.FullTypeName(parameters.Return, ServiceImporter.CodeGenerator), 893 null, 894 CodeFlags.IsPublic); 895 896 codeMethod.Comments.Add(new CodeCommentStatement(Res.GetString(Res.CodeRemarks), true)); 897 898 CodeExpression invokeParam = new CodeArgumentReferenceExpression("asyncResult"); 899 invoke = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "EndInvoke", new CodeExpression[] { invokeParam }); 900 901 WriteReturnMappings(codeMethod, invoke, parameters, resultsName); 902 } 903 904 // new RAD Async pattern 905 if (newAsync) { 906 string methodKey = MethodSignature(uniqueMethodName, returnType, parameterFlags, parameterTypes); 907 DelegateInfo delegateInfo = (DelegateInfo)ExportContext[methodKey]; 908 if (delegateInfo == null) { 909 string handlerType = ClassNames.AddUnique(uniqueMethodName + "CompletedEventHandler", uniqueMethodName); 910 string handlerArgs = ClassNames.AddUnique(uniqueMethodName + "CompletedEventArgs", uniqueMethodName); 911 delegateInfo = new DelegateInfo(handlerType, handlerArgs); 912 } 913 string handlerName = MethodNames.AddUnique(uniqueMethodName + "Completed", uniqueMethodName); 914 string asyncName = MethodNames.AddUnique(uniqueMethodName + "Async", uniqueMethodName); 915 string callbackMember = MethodNames.AddUnique(uniqueMethodName + "OperationCompleted", uniqueMethodName); 916 string callbackName = MethodNames.AddUnique("On" + uniqueMethodName + "OperationCompleted", uniqueMethodName); 917 918 // public event xxxCompletedEventHandler xxxCompleted; 919 WebCodeGenerator.AddEvent(this.CodeTypeDeclaration.Members, delegateInfo.handlerType, handlerName); 920 921 // private SendOrPostCallback xxxOperationCompleted; 922 WebCodeGenerator.AddCallbackDeclaration(this.CodeTypeDeclaration.Members, callbackMember); 923 924 // create the pair of xxxAsync methods 925 string[] inParamNames = SoapParameter.GetNames(parameters.InParameters, parameters.InCheckSpecifiedCount); 926 string userState = UniqueName("userState", inParamNames); 927 CodeMemberMethod asyncCodeMethod = WebCodeGenerator.AddAsyncMethod(this.CodeTypeDeclaration, asyncName, 928 SoapParameter.GetTypeFullNames(parameters.InParameters, parameters.InCheckSpecifiedCount, ServiceImporter.CodeGenerator), inParamNames, callbackMember, callbackName, userState); 929 930 // Generate InvokeAsync call 931 invokeParams = new CodeExpression[4]; 932 CreateInvokeParams(invokeParams, uniqueMethodName, parameters.InParameters, parameters.InCheckSpecifiedCount); 933 invokeParams[2] = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), callbackMember); 934 invokeParams[3] = new CodeArgumentReferenceExpression(userState); 935 936 invoke = new CodeMethodInvokeExpression(new CodeThisReferenceExpression(), "InvokeAsync", invokeParams); 937 asyncCodeMethod.Statements.Add(invoke); 938 939 // private void On_xxx_OperationCompleted(object arg) {..} 940 bool methodHasOutParameters = parameters.Return != null || parameters.OutParameters.Count > 0; 941 WebCodeGenerator.AddCallbackImplementation(this.CodeTypeDeclaration, callbackName, handlerName, delegateInfo.handlerArgs, methodHasOutParameters); 942 943 if (ExportContext[methodKey] == null) { 944 // public delegate void xxxCompletedEventHandler(object sender, System.ComponentModel.AsyncCompletedEventArgs args); 945 WebCodeGenerator.AddDelegate(ExtraCodeClasses, delegateInfo.handlerType, methodHasOutParameters ? delegateInfo.handlerArgs : typeof(AsyncCompletedEventArgs).FullName); 946 947 // Create strongly-typed Args class 948 if (methodHasOutParameters) { 949 int outCount = parameters.OutParameters.Count + parameters.OutCheckSpecifiedCount; 950 string[] asyncReturnTypes = new string[outCount + 1]; 951 SoapParameter.GetTypeFullNames(parameters.OutParameters, asyncReturnTypes, 1, parameters.OutCheckSpecifiedCount, ServiceImporter.CodeGenerator); 952 asyncReturnTypes[0] = parameters.Return == null ? null : WebCodeGenerator.FullTypeName(parameters.Return, ServiceImporter.CodeGenerator); 953 954 string[] asyncReturnNames = new string[outCount + 1]; 955 SoapParameter.GetNames(parameters.OutParameters, asyncReturnNames, 1, parameters.OutCheckSpecifiedCount); 956 asyncReturnNames[0] = parameters.Return == null ? null : "Result"; 957 ExtraCodeClasses.Add(WebCodeGenerator.CreateArgsClass(delegateInfo.handlerArgs, asyncReturnTypes, asyncReturnNames, ServiceImporter.CodeGenerator.Supports(GeneratorSupport.PartialTypes))); 958 } 959 ExportContext[methodKey] = delegateInfo; 960 } 961 } 962 } 963 return mainCodeMethod; 964 } 965 WriteReturnMappings(CodeMemberMethod codeMethod, CodeExpression invoke, SoapParameters parameters, string resultsName)966 void WriteReturnMappings(CodeMemberMethod codeMethod, CodeExpression invoke, SoapParameters parameters, string resultsName) { 967 if (parameters.Return == null && parameters.OutParameters.Count == 0) { 968 codeMethod.Statements.Add(new CodeExpressionStatement(invoke)); 969 } 970 else { 971 codeMethod.Statements.Add(new CodeVariableDeclarationStatement(typeof(object[]), resultsName, invoke)); 972 973 int count = parameters.Return == null ? 0 : 1; 974 for (int i = 0; i < parameters.OutParameters.Count; i++) { 975 SoapParameter parameter = (SoapParameter)parameters.OutParameters[i]; 976 CodeExpression target = new CodeArgumentReferenceExpression(parameter.name); 977 CodeExpression value = new CodeArrayIndexerExpression(); 978 ((CodeArrayIndexerExpression)value).TargetObject = new CodeVariableReferenceExpression(resultsName); 979 ((CodeArrayIndexerExpression)value).Indices.Add(new CodePrimitiveExpression(count++)); 980 value = new CodeCastExpression(WebCodeGenerator.FullTypeName(parameter.mapping, ServiceImporter.CodeGenerator), value); 981 codeMethod.Statements.Add(new CodeAssignStatement(target, value)); 982 if (parameter.mapping.CheckSpecified) { 983 target = new CodeArgumentReferenceExpression(parameter.name + "Specified"); 984 value = new CodeArrayIndexerExpression(); 985 ((CodeArrayIndexerExpression) value).TargetObject = new CodeVariableReferenceExpression(resultsName); 986 ((CodeArrayIndexerExpression)value).Indices.Add(new CodePrimitiveExpression(count++)); 987 value = new CodeCastExpression(typeof(bool).FullName, value); 988 codeMethod.Statements.Add(new CodeAssignStatement(target, value)); 989 } 990 } 991 992 if (parameters.Return != null) { 993 CodeExpression value = new CodeArrayIndexerExpression(); 994 ((CodeArrayIndexerExpression)value).TargetObject = new CodeVariableReferenceExpression(resultsName); 995 ((CodeArrayIndexerExpression)value).Indices.Add(new CodePrimitiveExpression(0)); 996 value = new CodeCastExpression(WebCodeGenerator.FullTypeName(parameters.Return, ServiceImporter.CodeGenerator), value); 997 codeMethod.Statements.Add(new CodeMethodReturnStatement(value)); 998 } 999 } 1000 } 1001 CreateInvokeParams(CodeExpression[] invokeParams, string methodName, IList parameters, int checkSpecifiedCount)1002 void CreateInvokeParams(CodeExpression[] invokeParams, string methodName, IList parameters, int checkSpecifiedCount) { 1003 invokeParams[0] = new CodePrimitiveExpression(methodName); 1004 1005 CodeExpression[] values = new CodeExpression[parameters.Count + checkSpecifiedCount]; 1006 int value = 0; 1007 for (int i = 0; i < parameters.Count; i++) { 1008 SoapParameter parameter = (SoapParameter)parameters[i]; 1009 values[value++] = new CodeArgumentReferenceExpression(parameter.name); 1010 if (parameter.mapping.CheckSpecified) 1011 values[value++] = new CodeArgumentReferenceExpression(parameter.specifiedName); 1012 } 1013 invokeParams[1] = new CodeArrayCreateExpression(typeof(object).FullName, values); 1014 } 1015 1016 // returns false if we didn't like the message -- otherwise caller is safe to use body binding and binding style CheckMessageStyles(string messageName, MessagePart[] parts, SoapBodyBinding soapBodyBinding, SoapBindingStyle soapBindingStyle, out bool hasWrapper)1017 bool CheckMessageStyles(string messageName, MessagePart[] parts, SoapBodyBinding soapBodyBinding, SoapBindingStyle soapBindingStyle, out bool hasWrapper) { 1018 hasWrapper = false; 1019 if (soapBodyBinding.Use == SoapBindingUse.Default) { 1020 soapBodyBinding.Use = SoapBindingUse.Literal; 1021 } 1022 if (soapBodyBinding.Use == SoapBindingUse.Literal) { 1023 if (soapBindingStyle == SoapBindingStyle.Rpc) { 1024 foreach (MessagePart part in parts) { 1025 if (!part.Element.IsEmpty) { 1026 UnsupportedOperationBindingWarning(Res.GetString(Res.EachMessagePartInRpcUseLiteralMessageMustSpecify0)); 1027 return false; 1028 } 1029 } 1030 return true; 1031 } 1032 if (parts.Length == 1 && !parts[0].Type.IsEmpty) { 1033 // special top-level any case 1034 if (!parts[0].Element.IsEmpty) { 1035 UnsupportedOperationBindingWarning(Res.GetString(Res.SpecifyingATypeForUseLiteralMessagesIs0)); 1036 return false; 1037 } 1038 XmlMembersMapping membersMapping = xmlImporter.ImportAnyType(parts[0].Type, parts[0].Name); 1039 if (membersMapping == null) { 1040 UnsupportedOperationBindingWarning(Res.GetString(Res.SpecifyingATypeForUseLiteralMessagesIsAny, parts[0].Type.Name, parts[0].Type.Namespace)); 1041 return false; 1042 } 1043 return true; 1044 } 1045 else { 1046 foreach (MessagePart part in parts) { 1047 if (!part.Type.IsEmpty) { 1048 UnsupportedOperationBindingWarning(Res.GetString(Res.SpecifyingATypeForUseLiteralMessagesIs0)); 1049 return false; 1050 } 1051 if (part.Element.IsEmpty) { 1052 UnsupportedOperationBindingWarning(Res.GetString(Res.EachMessagePartInAUseLiteralMessageMustSpecify0)); 1053 return false; 1054 } 1055 } 1056 } 1057 } 1058 else if (soapBodyBinding.Use == SoapBindingUse.Encoded) { 1059 if (!IsSoapEncodingPresent(soapBodyBinding.Encoding)) { 1060 UnsupportedOperationBindingWarning(Res.GetString(Res.TheEncodingIsNotSupported1, soapBodyBinding.Encoding)); 1061 return false; 1062 } 1063 foreach (MessagePart part in parts) { 1064 if (!part.Element.IsEmpty) { 1065 UnsupportedOperationBindingWarning(Res.GetString(Res.SpecifyingAnElementForUseEncodedMessageParts0)); 1066 return false; 1067 } 1068 if (part.Type.IsEmpty) { 1069 UnsupportedOperationBindingWarning(Res.GetString(Res.EachMessagePartInAnUseEncodedMessageMustSpecify0)); 1070 return false; 1071 } 1072 } 1073 } 1074 1075 if (soapBindingStyle == SoapBindingStyle.Rpc) { 1076 return true; 1077 } 1078 else if (soapBindingStyle == SoapBindingStyle.Document) { 1079 // NOTE, Microsoft. WSDL doesn't really let us figure out whether a document is 1080 // in fact a struct containing parameters, so we apply a little heuristic here 1081 // in order to produce the appropriate programming model. 1082 hasWrapper = (parts.Length == 1 && string.Compare(parts[0].Name, "parameters", StringComparison.Ordinal) == 0); 1083 return true; 1084 } 1085 return false; 1086 } 1087 1088 /// <include file='doc\SoapProtocolImporter.uex' path='docs/doc[@for="SoapProtocolImporter.IsSoapEncodingPresent"]/*' /> 1089 /// <internalonly/> IsSoapEncodingPresent(string uriList)1090 protected virtual bool IsSoapEncodingPresent(string uriList) { 1091 int iStart = 0; 1092 do { 1093 iStart = uriList.IndexOf(Soap.Encoding, iStart, StringComparison.Ordinal); 1094 if (iStart < 0) 1095 return false; 1096 int iEnd = iStart + Soap.Encoding.Length; 1097 if (iStart == 0 || uriList[iStart - 1] == ' ') 1098 if (iEnd == uriList.Length || uriList[iEnd] == ' ') 1099 return true; 1100 iStart = iEnd; 1101 } while (iStart < uriList.Length); 1102 return false; 1103 } 1104 GetMessageParts(Message message, SoapBodyBinding soapBodyBinding)1105 MessagePart[] GetMessageParts(Message message, SoapBodyBinding soapBodyBinding) { 1106 MessagePart[] parts; 1107 if (soapBodyBinding.Parts == null) { 1108 parts = new MessagePart[message.Parts.Count]; 1109 message.Parts.CopyTo(parts, 0); 1110 } 1111 else { 1112 parts = message.FindPartsByName(soapBodyBinding.Parts); 1113 } 1114 return parts; 1115 } 1116 ImportMessage(string messageName, MessagePart[] parts, SoapBodyBinding soapBodyBinding, SoapBindingStyle soapBindingStyle, bool wrapped)1117 XmlMembersMapping ImportMessage(string messageName, MessagePart[] parts, SoapBodyBinding soapBodyBinding, SoapBindingStyle soapBindingStyle, bool wrapped) { 1118 if (soapBodyBinding.Use == SoapBindingUse.Encoded) 1119 return ImportEncodedMessage(messageName, parts, soapBodyBinding, wrapped); 1120 else 1121 return ImportLiteralMessage(messageName, parts, soapBodyBinding, soapBindingStyle, wrapped); 1122 } 1123 ImportEncodedMessage(string messageName, MessagePart[] parts, SoapBodyBinding soapBodyBinding, bool wrapped)1124 XmlMembersMapping ImportEncodedMessage(string messageName, MessagePart[] parts, SoapBodyBinding soapBodyBinding, bool wrapped) { 1125 XmlMembersMapping membersMapping; 1126 if (wrapped) { 1127 SoapSchemaMember schemaMember = new SoapSchemaMember(); 1128 schemaMember.MemberName = parts[0].Name; 1129 schemaMember.MemberType = parts[0].Type; 1130 membersMapping = soapImporter.ImportMembersMapping(messageName, soapBodyBinding.Namespace, schemaMember); 1131 } 1132 else { 1133 SoapSchemaMember[] schemaMembers = new SoapSchemaMember[parts.Length]; 1134 for (int i = 0; i < schemaMembers.Length; i++) { 1135 MessagePart part = parts[i]; 1136 SoapSchemaMember schemaMember = new SoapSchemaMember(); 1137 schemaMember.MemberName = part.Name; 1138 schemaMember.MemberType = part.Type; 1139 schemaMembers[i] = schemaMember; 1140 } 1141 membersMapping = soapImporter.ImportMembersMapping(messageName, soapBodyBinding.Namespace, schemaMembers); 1142 } 1143 soapMembers.Add(membersMapping); 1144 return membersMapping; 1145 } 1146 ImportLiteralMessage(string messageName, MessagePart[] parts, SoapBodyBinding soapBodyBinding, SoapBindingStyle soapBindingStyle, bool wrapped)1147 XmlMembersMapping ImportLiteralMessage(string messageName, MessagePart[] parts, SoapBodyBinding soapBodyBinding, SoapBindingStyle soapBindingStyle, bool wrapped) { 1148 XmlMembersMapping membersMapping; 1149 if (soapBindingStyle == SoapBindingStyle.Rpc) { 1150 SoapSchemaMember[] schemaMembers = new SoapSchemaMember[parts.Length]; 1151 for (int i = 0; i < schemaMembers.Length; i++) { 1152 MessagePart part = parts[i]; 1153 SoapSchemaMember schemaMember = new SoapSchemaMember(); 1154 schemaMember.MemberName = part.Name; 1155 schemaMember.MemberType = part.Type; 1156 schemaMembers[i] = schemaMember; 1157 } 1158 membersMapping = xmlImporter.ImportMembersMapping(messageName, soapBodyBinding.Namespace, schemaMembers); 1159 } 1160 else if (wrapped) { 1161 membersMapping = xmlImporter.ImportMembersMapping(parts[0].Element); 1162 } 1163 else { 1164 if (parts.Length == 1 && !parts[0].Type.IsEmpty) { 1165 // special case for <any> at root 1166 // we know this will work because we tried it earlier in CheckMessageStyles. 1167 membersMapping = xmlImporter.ImportAnyType(parts[0].Type, parts[0].Name); 1168 xmlMembers.Add(membersMapping); 1169 return membersMapping; 1170 } 1171 XmlQualifiedName[] names = new XmlQualifiedName[parts.Length]; 1172 for (int i = 0; i < parts.Length; i++) 1173 names[i] = parts[i].Element; 1174 membersMapping = xmlImporter.ImportMembersMapping(names); 1175 } 1176 xmlMembers.Add(membersMapping); 1177 return membersMapping; 1178 } 1179 } 1180 } 1181