1 // 2 // Methods.cs: Information about a method and its mapping to a SOAP web service. 3 // 4 // Author: 5 // Miguel de Icaza 6 // Lluis Sanchez Gual (lluis@ximian.com) 7 // 8 // (C) 2003 Ximian, Inc. 9 // 10 11 // 12 // Permission is hereby granted, free of charge, to any person obtaining 13 // a copy of this software and associated documentation files (the 14 // "Software"), to deal in the Software without restriction, including 15 // without limitation the rights to use, copy, modify, merge, publish, 16 // distribute, sublicense, and/or sell copies of the Software, and to 17 // permit persons to whom the Software is furnished to do so, subject to 18 // the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be 21 // included in all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 // 31 32 using HeaderInfo = System.Web.Services.Protocols.SoapHeaderMapping; 33 34 using System.Reflection; 35 using System.Collections; 36 using System.Xml; 37 using System.Xml.Serialization; 38 using System.Web.Services; 39 using System.Web.Services.Description; 40 41 namespace System.Web.Services.Protocols { 42 43 // 44 // This class represents all the information we extract from a MethodInfo 45 // in the SoapHttpClientProtocol derivative stub class 46 // 47 internal class SoapMethodStubInfo : MethodStubInfo 48 { 49 internal readonly string Action; 50 internal readonly string Binding; 51 52 // The name/namespace of the request 53 internal readonly string RequestName; 54 internal readonly string RequestNamespace; 55 56 // The name/namespace of the response. 57 internal readonly string ResponseName; 58 internal readonly string ResponseNamespace; 59 60 internal readonly bool OneWay; 61 internal readonly SoapParameterStyle ParameterStyle; 62 internal readonly SoapBindingStyle SoapBindingStyle; 63 internal readonly SoapBindingUse Use; 64 65 internal readonly HeaderInfo [] Headers; 66 internal readonly HeaderInfo [] InHeaders; 67 internal readonly HeaderInfo [] OutHeaders; 68 internal readonly HeaderInfo [] FaultHeaders; 69 internal readonly SoapExtensionRuntimeConfig [] SoapExtensions; 70 71 internal readonly XmlMembersMapping InputMembersMapping; 72 internal readonly XmlMembersMapping OutputMembersMapping; 73 internal readonly XmlMembersMapping InputHeaderMembersMapping; 74 internal readonly XmlMembersMapping OutputHeaderMembersMapping; 75 internal readonly XmlMembersMapping FaultHeaderMembersMapping; 76 77 private readonly int requestSerializerId; 78 private readonly int responseSerializerId; 79 private readonly int requestHeadersSerializerId = -1; 80 private readonly int responseHeadersSerializerId = -1; 81 private readonly int faultHeadersSerializerId = -1; 82 83 internal XmlSerializer RequestSerializer 84 { 85 get { return TypeStub.GetSerializer (requestSerializerId); } 86 } 87 88 internal XmlSerializer ResponseSerializer 89 { 90 get { return TypeStub.GetSerializer (responseSerializerId); } 91 } 92 93 internal XmlSerializer RequestHeadersSerializer 94 { 95 get { return requestHeadersSerializerId != -1 ? TypeStub.GetSerializer (requestHeadersSerializerId) : null; } 96 } 97 98 internal XmlSerializer ResponseHeadersSerializer 99 { 100 get { return responseHeadersSerializerId != -1 ? TypeStub.GetSerializer (responseHeadersSerializerId) : null; } 101 } 102 103 internal XmlSerializer FaultHeadersSerializer 104 { 105 get { return faultHeadersSerializerId != -1 ? TypeStub.GetSerializer (faultHeadersSerializerId) : null; } 106 } 107 108 109 // 110 // Constructor 111 // SoapMethodStubInfo(TypeStubInfo typeStub, LogicalMethodInfo source, object kind, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter)112 public SoapMethodStubInfo (TypeStubInfo typeStub, LogicalMethodInfo source, object kind, XmlReflectionImporter xmlImporter, SoapReflectionImporter soapImporter) 113 : base (typeStub, source) 114 { 115 SoapTypeStubInfo parent = (SoapTypeStubInfo) typeStub; 116 XmlElementAttribute optional_ns = null; 117 118 if (kind == null) { 119 Use = parent.LogicalType.BindingUse; 120 RequestName = ""; 121 RequestNamespace = ""; 122 ResponseName = ""; 123 ResponseNamespace = ""; 124 ParameterStyle = parent.ParameterStyle; 125 SoapBindingStyle = parent.SoapBindingStyle; 126 OneWay = false; 127 // disabled (see bug #332150) 128 //#if NET_2_0 129 // if (parent.Type != source.DeclaringType) 130 // Binding = source.DeclaringType.Name + parent.ProtocolName; 131 //#endif 132 } 133 else if (kind is SoapDocumentMethodAttribute){ 134 SoapDocumentMethodAttribute dma = (SoapDocumentMethodAttribute) kind; 135 136 Use = dma.Use; 137 if (Use == SoapBindingUse.Default) { 138 if (parent.SoapBindingStyle == SoapBindingStyle.Document) 139 Use = parent.LogicalType.BindingUse; 140 else 141 Use = SoapBindingUse.Literal; 142 } 143 144 Action = dma.Action; 145 Binding = dma.Binding; 146 RequestName = dma.RequestElementName; 147 RequestNamespace = dma.RequestNamespace; 148 ResponseName = dma.ResponseElementName; 149 ResponseNamespace = dma.ResponseNamespace; 150 ParameterStyle = dma.ParameterStyle; 151 if (ParameterStyle == SoapParameterStyle.Default) 152 ParameterStyle = parent.ParameterStyle; 153 OneWay = dma.OneWay; 154 SoapBindingStyle = SoapBindingStyle.Document; 155 } else { 156 SoapRpcMethodAttribute rma = (SoapRpcMethodAttribute) kind; 157 Use = SoapBindingUse.Encoded; // RPC always use encoded 158 159 Action = rma.Action; 160 if (Action != null && Action.Length == 0) 161 Action = null; 162 Binding = rma.Binding; 163 164 // When using RPC, MS.NET seems to ignore RequestElementName and 165 // MessageName, and it always uses the method name 166 RequestName = source.Name; 167 ResponseName = source.Name + "Response"; 168 // RequestName = rma.RequestElementName; 169 // ResponseName = rma.ResponseElementName; 170 RequestNamespace = rma.RequestNamespace; 171 ResponseNamespace = rma.ResponseNamespace; 172 ParameterStyle = SoapParameterStyle.Wrapped; 173 OneWay = rma.OneWay; 174 SoapBindingStyle = SoapBindingStyle.Rpc; 175 176 // For RPC calls, make all arguments be part of the empty namespace 177 optional_ns = new XmlElementAttribute (); 178 optional_ns.Namespace = ""; 179 } 180 181 if (OneWay){ 182 if (source.ReturnType != typeof (void)) 183 throw new Exception ("OneWay methods should not have a return value."); 184 if (source.OutParameters.Length != 0) 185 throw new Exception ("OneWay methods should not have out/ref parameters."); 186 } 187 188 BindingInfo binfo = parent.GetBinding (Binding); 189 if (binfo == null) throw new InvalidOperationException ("Type '" + parent.Type + "' is missing WebServiceBinding attribute that defines a binding named '" + Binding + "'."); 190 191 string serviceNamespace = binfo.Namespace; 192 193 if (RequestNamespace == "") RequestNamespace = parent.LogicalType.GetWebServiceNamespace (serviceNamespace, Use); 194 if (ResponseNamespace == "") ResponseNamespace = parent.LogicalType.GetWebServiceNamespace (serviceNamespace, Use); 195 if (RequestName == "") RequestName = Name; 196 if (ResponseName == "") ResponseName = Name + "Response"; 197 if (Action == null) 198 Action = serviceNamespace.EndsWith("/") ? (serviceNamespace + Name) : (serviceNamespace + "/" + Name); 199 200 bool hasWrappingElem = (ParameterStyle == SoapParameterStyle.Wrapped); 201 bool writeAccessors = (SoapBindingStyle == SoapBindingStyle.Rpc); 202 203 XmlReflectionMember [] in_members = BuildRequestReflectionMembers (optional_ns); 204 XmlReflectionMember [] out_members = BuildResponseReflectionMembers (optional_ns); 205 206 if (Use == SoapBindingUse.Literal) { 207 xmlImporter.IncludeTypes (source.CustomAttributeProvider); 208 InputMembersMapping = xmlImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem); 209 OutputMembersMapping = xmlImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem); 210 } 211 else { 212 soapImporter.IncludeTypes (source.CustomAttributeProvider); 213 InputMembersMapping = soapImporter.ImportMembersMapping (RequestName, RequestNamespace, in_members, hasWrappingElem, writeAccessors); 214 OutputMembersMapping = soapImporter.ImportMembersMapping (ResponseName, ResponseNamespace, out_members, hasWrappingElem, writeAccessors); 215 } 216 217 InputMembersMapping.SetKey(RequestName); 218 OutputMembersMapping.SetKey(ResponseName); 219 220 requestSerializerId = parent.RegisterSerializer (InputMembersMapping); 221 responseSerializerId = parent.RegisterSerializer (OutputMembersMapping); 222 223 object[] o = source.GetCustomAttributes (typeof (SoapHeaderAttribute)); 224 ArrayList allHeaderList = new ArrayList (o.Length); 225 ArrayList inHeaderList = new ArrayList (o.Length); 226 ArrayList outHeaderList = new ArrayList (o.Length); 227 ArrayList faultHeaderList = new ArrayList (); 228 229 SoapHeaderDirection unknownHeaderDirections = (SoapHeaderDirection)0; 230 231 for (int i = 0; i < o.Length; i++) { 232 SoapHeaderAttribute att = (SoapHeaderAttribute) o[i]; 233 MemberInfo[] mems = source.DeclaringType.GetMember (att.MemberName); 234 if (mems.Length == 0) throw new InvalidOperationException ("Member " + att.MemberName + " not found in class " + source.DeclaringType.FullName + "."); 235 236 HeaderInfo header = new HeaderInfo (mems[0], att); 237 allHeaderList.Add (header); 238 if (!header.Custom) { 239 if ((header.Direction & SoapHeaderDirection.In) != 0) 240 inHeaderList.Add (header); 241 if ((header.Direction & SoapHeaderDirection.Out) != 0) 242 outHeaderList.Add (header); 243 if ((header.Direction & SoapHeaderDirection.Fault) != 0) 244 faultHeaderList.Add (header); 245 } else 246 unknownHeaderDirections |= header.Direction; 247 } 248 249 Headers = (HeaderInfo[]) allHeaderList.ToArray (typeof(HeaderInfo)); 250 251 if (inHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.In) != 0) { 252 InHeaders = (HeaderInfo[]) inHeaderList.ToArray (typeof(HeaderInfo)); 253 XmlReflectionMember[] members = BuildHeadersReflectionMembers (InHeaders); 254 255 if (Use == SoapBindingUse.Literal) 256 InputHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false); 257 else 258 InputHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false); 259 260 InputHeaderMembersMapping.SetKey(RequestName + ":InHeaders"); 261 262 requestHeadersSerializerId = parent.RegisterSerializer (InputHeaderMembersMapping); 263 } 264 265 if (outHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.Out) != 0) { 266 OutHeaders = (HeaderInfo[]) outHeaderList.ToArray (typeof(HeaderInfo)); 267 XmlReflectionMember[] members = BuildHeadersReflectionMembers (OutHeaders); 268 269 if (Use == SoapBindingUse.Literal) 270 OutputHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false); 271 else 272 OutputHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false); 273 274 OutputHeaderMembersMapping.SetKey(ResponseName + ":OutHeaders"); 275 276 responseHeadersSerializerId = parent.RegisterSerializer (OutputHeaderMembersMapping); 277 } 278 279 if (faultHeaderList.Count > 0 || (unknownHeaderDirections & SoapHeaderDirection.Fault) != 0) { 280 FaultHeaders = (HeaderInfo[]) faultHeaderList.ToArray (typeof(HeaderInfo)); 281 XmlReflectionMember[] members = BuildHeadersReflectionMembers (FaultHeaders); 282 283 if (Use == SoapBindingUse.Literal) 284 FaultHeaderMembersMapping = xmlImporter.ImportMembersMapping ("", RequestNamespace, members, false); 285 else 286 FaultHeaderMembersMapping = soapImporter.ImportMembersMapping ("", RequestNamespace, members, false, false); 287 288 faultHeadersSerializerId = parent.RegisterSerializer (FaultHeaderMembersMapping); 289 } 290 291 SoapExtensions = SoapExtension.GetMethodExtensions (source); 292 } 293 BuildRequestReflectionMembers(XmlElementAttribute optional_ns)294 XmlReflectionMember [] BuildRequestReflectionMembers (XmlElementAttribute optional_ns) 295 { 296 ParameterInfo [] input = MethodInfo.InParameters; 297 XmlReflectionMember [] in_members = new XmlReflectionMember [input.Length]; 298 299 for (int i = 0; i < input.Length; i++) 300 { 301 XmlReflectionMember m = new XmlReflectionMember (); 302 m.IsReturnValue = false; 303 m.MemberName = input [i].Name; 304 m.MemberType = input [i].ParameterType; 305 306 m.XmlAttributes = new XmlAttributes (input[i]); 307 m.SoapAttributes = new SoapAttributes (input[i]); 308 309 if (m.MemberType.IsByRef) 310 m.MemberType = m.MemberType.GetElementType (); 311 if (optional_ns != null) 312 m.XmlAttributes.XmlElements.Add (optional_ns); 313 in_members [i] = m; 314 } 315 return in_members; 316 } 317 BuildResponseReflectionMembers(XmlElementAttribute optional_ns)318 XmlReflectionMember [] BuildResponseReflectionMembers (XmlElementAttribute optional_ns) 319 { 320 ParameterInfo [] output = MethodInfo.OutParameters; 321 bool has_return_value = !(OneWay || MethodInfo.ReturnType == typeof (void)); 322 XmlReflectionMember [] out_members = new XmlReflectionMember [(has_return_value ? 1 : 0) + output.Length]; 323 XmlReflectionMember m; 324 int idx = 0; 325 326 if (has_return_value) 327 { 328 m = new XmlReflectionMember (); 329 m.IsReturnValue = true; 330 m.MemberName = Name + "Result"; 331 m.MemberType = MethodInfo.ReturnType; 332 333 m.XmlAttributes = new XmlAttributes (MethodInfo.ReturnTypeCustomAttributeProvider); 334 m.SoapAttributes = new SoapAttributes (MethodInfo.ReturnTypeCustomAttributeProvider); 335 336 if (optional_ns != null) 337 m.XmlAttributes.XmlElements.Add (optional_ns); 338 idx++; 339 out_members [0] = m; 340 } 341 342 for (int i = 0; i < output.Length; i++) 343 { 344 m = new XmlReflectionMember (); 345 m.IsReturnValue = false; 346 m.MemberName = output [i].Name; 347 m.MemberType = output [i].ParameterType; 348 m.XmlAttributes = new XmlAttributes (output[i]); 349 m.SoapAttributes = new SoapAttributes (output[i]); 350 351 if (m.MemberType.IsByRef) 352 m.MemberType = m.MemberType.GetElementType (); 353 if (optional_ns != null) 354 m.XmlAttributes.XmlElements.Add (optional_ns); 355 out_members [i + idx] = m; 356 } 357 return out_members; 358 } 359 BuildHeadersReflectionMembers(HeaderInfo[] headers)360 XmlReflectionMember [] BuildHeadersReflectionMembers (HeaderInfo[] headers) 361 { 362 XmlReflectionMember [] mems = new XmlReflectionMember [headers.Length]; 363 364 for (int n=0; n<headers.Length; n++) 365 { 366 HeaderInfo header = headers [n]; 367 368 XmlReflectionMember m = new XmlReflectionMember (); 369 m.IsReturnValue = false; 370 m.MemberName = header.HeaderType.Name; 371 m.MemberType = header.HeaderType; 372 373 // MS.NET reflects header classes in a weird way. The root element 374 // name is the CLR class name unless it is specified in an XmlRootAttribute. 375 // The usual is to use the xml type name by default, but not in this case. 376 377 XmlAttributes ats = new XmlAttributes (header.HeaderType); 378 if (ats.XmlRoot != null) { 379 XmlElementAttribute xe = new XmlElementAttribute (); 380 xe.ElementName = ats.XmlRoot.ElementName; 381 xe.Namespace = ats.XmlRoot.Namespace; 382 m.XmlAttributes = new XmlAttributes (); 383 m.XmlAttributes.XmlElements.Add (xe); 384 } 385 386 mems [n] = m; 387 } 388 return mems; 389 } 390 GetHeaderInfo(Type headerType)391 public HeaderInfo GetHeaderInfo (Type headerType) 392 { 393 foreach (HeaderInfo headerInfo in Headers) 394 if (headerInfo.HeaderType == headerType) return headerInfo; 395 return null; 396 } 397 GetBodySerializer(SoapHeaderDirection dir, bool soap12)398 public XmlSerializer GetBodySerializer (SoapHeaderDirection dir, bool soap12) 399 { 400 switch (dir) { 401 case SoapHeaderDirection.In: return RequestSerializer; 402 case SoapHeaderDirection.Out: return ResponseSerializer; 403 case SoapHeaderDirection.Fault: return soap12 ? Soap12Fault.Serializer : Fault.Serializer; 404 default: return null; 405 } 406 } 407 GetHeaderSerializer(SoapHeaderDirection dir)408 public XmlSerializer GetHeaderSerializer (SoapHeaderDirection dir) 409 { 410 switch (dir) { 411 case SoapHeaderDirection.In: return RequestHeadersSerializer; 412 case SoapHeaderDirection.Out: return ResponseHeadersSerializer; 413 case SoapHeaderDirection.Fault: return FaultHeadersSerializer; 414 default: return null; 415 } 416 } 417 GetHeaders(SoapHeaderDirection dir)418 HeaderInfo[] GetHeaders (SoapHeaderDirection dir) 419 { 420 switch (dir) { 421 case SoapHeaderDirection.In: return InHeaders; 422 case SoapHeaderDirection.Out: return OutHeaders; 423 case SoapHeaderDirection.Fault: return FaultHeaders; 424 default: return null; 425 } 426 } 427 GetHeaderValueArray(SoapHeaderDirection dir, SoapHeaderCollection headers)428 public object[] GetHeaderValueArray (SoapHeaderDirection dir, SoapHeaderCollection headers) 429 { 430 HeaderInfo[] headerInfos = GetHeaders (dir); 431 if (headerInfos == null) return null; 432 433 object[] hs = new object [headerInfos.Length]; 434 435 for (int n=0; n<headers.Count; n++) { 436 SoapHeader h = headers[n]; 437 Type t = h.GetType(); 438 for (int i=0; i<headerInfos.Length; i++) 439 if (headerInfos [i].HeaderType == t) 440 hs [i] = h; 441 } 442 return hs; 443 } 444 } 445 446 // 447 // Holds the metadata loaded from the type stub, as well as 448 // the metadata for all the methods in the type 449 // 450 internal class SoapTypeStubInfo : TypeStubInfo 451 { 452 Hashtable methods_byaction = new Hashtable (); 453 454 // Precomputed 455 internal SoapParameterStyle ParameterStyle; 456 internal SoapExtensionRuntimeConfig[][] SoapExtensions; 457 internal SoapBindingStyle SoapBindingStyle; 458 internal XmlReflectionImporter xmlImporter; 459 internal SoapReflectionImporter soapImporter; 460 SoapTypeStubInfo(LogicalTypeInfo logicalTypeInfo)461 public SoapTypeStubInfo (LogicalTypeInfo logicalTypeInfo) 462 : base (logicalTypeInfo) 463 { 464 xmlImporter = new XmlReflectionImporter (); 465 soapImporter = new SoapReflectionImporter (); 466 467 if (typeof (SoapHttpClientProtocol).IsAssignableFrom (Type)) 468 { 469 if (Bindings.Count == 0 || ((BindingInfo)Bindings[0]).WebServiceBindingAttribute == null) 470 throw new InvalidOperationException ("WebServiceBindingAttribute is required on proxy class '" + Type + "'."); 471 if (Bindings.Count > 1) 472 throw new InvalidOperationException ("Only one WebServiceBinding attribute may be specified on type '" + Type + "'."); 473 } 474 475 object [] o = Type.GetCustomAttributes (typeof (SoapDocumentServiceAttribute), false); 476 if (o.Length == 1){ 477 SoapDocumentServiceAttribute a = (SoapDocumentServiceAttribute) o [0]; 478 479 ParameterStyle = a.ParameterStyle; 480 SoapBindingStyle = SoapBindingStyle.Document; 481 } else { 482 o = Type.GetCustomAttributes (typeof (SoapRpcServiceAttribute), false); 483 if (o.Length == 1){ 484 ParameterStyle = SoapParameterStyle.Wrapped; 485 SoapBindingStyle = SoapBindingStyle.Rpc; 486 } else { 487 ParameterStyle = SoapParameterStyle.Wrapped; 488 SoapBindingStyle = SoapBindingStyle.Document; 489 } 490 } 491 492 if (ParameterStyle == SoapParameterStyle.Default) ParameterStyle = SoapParameterStyle.Wrapped; 493 494 xmlImporter.IncludeTypes (Type); 495 soapImporter.IncludeTypes (Type); 496 497 #if MOBILE || XAMMAC_4_5 498 SoapExtensions = new SoapExtensionRuntimeConfig [2][]; 499 #else 500 SoapExtensions = SoapExtension.GetTypeExtensions (Type); 501 #endif 502 } 503 504 internal SoapServiceRoutingStyle RoutingStyle { 505 get { return LogicalType.RoutingStyle; } 506 } 507 508 public override XmlReflectionImporter XmlImporter 509 { 510 get { return xmlImporter; } 511 } 512 513 public override SoapReflectionImporter SoapImporter 514 { 515 get { return soapImporter; } 516 } 517 518 public override string ProtocolName 519 { 520 get { return "Soap"; } 521 } 522 CreateMethodStubInfo(TypeStubInfo parent, LogicalMethodInfo lmi, bool isClientProxy)523 protected override MethodStubInfo CreateMethodStubInfo (TypeStubInfo parent, LogicalMethodInfo lmi, bool isClientProxy) 524 { 525 SoapMethodStubInfo res = null; 526 object [] ats = lmi.GetCustomAttributes (typeof (SoapDocumentMethodAttribute)); 527 if (ats.Length == 0) ats = lmi.GetCustomAttributes (typeof (SoapRpcMethodAttribute)); 528 529 if (ats.Length == 0 && isClientProxy) 530 return null; 531 else if (ats.Length == 0) 532 res = new SoapMethodStubInfo (parent, lmi, null, xmlImporter, soapImporter); 533 else 534 res = new SoapMethodStubInfo (parent, lmi, ats[0], xmlImporter, soapImporter); 535 536 methods_byaction [res.Action] = res; 537 return res; 538 } 539 GetMethodForSoapAction(string name)540 public SoapMethodStubInfo GetMethodForSoapAction (string name) 541 { 542 return (SoapMethodStubInfo) methods_byaction [name.Trim ('"',' ')]; 543 } 544 } 545 546 internal class Soap12TypeStubInfo : SoapTypeStubInfo 547 { Soap12TypeStubInfo(LogicalTypeInfo logicalTypeInfo)548 public Soap12TypeStubInfo (LogicalTypeInfo logicalTypeInfo) 549 : base (logicalTypeInfo) 550 { 551 } 552 553 public override string ProtocolName 554 { 555 get { return "Soap12"; } 556 } 557 } 558 } 559