1 //----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation. All rights reserved.
3 //----------------------------------------------------------------------------
4 namespace System.ServiceModel.Description
6 using System.Collections.Generic;
8 using System.ServiceModel.Dispatcher;
10 using WsdlNS = System.Web.Services.Description;
12 static class SoapHelper
14 static object SoapVersionStateKey = new object();
15 static XmlDocument xmlDocument;
17 static XmlDocument Document
21 if (xmlDocument == null)
22 xmlDocument = new XmlDocument();
27 static XmlAttribute CreateLocalAttribute(string name, string value)
29 XmlAttribute attribute = Document.CreateAttribute(name);
30 attribute.Value = value;
33 // -----------------------------------------------------------------------------------------------------------------------
34 // Developers Note: We go through a little song an dance here to Get or Create an exsisting SoapBinding from the WSDL
35 // Extensions for a number of reasons:
36 // 1. Multiple Extensions may contribute to the settings in the soap binding and so to make this work without
37 // relying on ordering, we need the GetOrCreate method.
38 // 2. There are diffrent classes for diffrent SOAP versions and the extensions that determines the version is
39 // also un-ordered so when we finally figure out the version we may need to recreate the BindingExtension and
42 internal static WsdlNS.SoapAddressBinding GetOrCreateSoapAddressBinding(WsdlNS.Binding wsdlBinding, WsdlNS.Port wsdlPort, WsdlExporter exporter)
44 if (GetSoapVersionState(wsdlBinding, exporter) == EnvelopeVersion.None)
47 WsdlNS.SoapAddressBinding existingSoapAddressBinding = GetSoapAddressBinding(wsdlPort);
48 EnvelopeVersion version = GetSoapVersion(wsdlBinding);
50 if (existingSoapAddressBinding != null)
51 return existingSoapAddressBinding;
53 WsdlNS.SoapAddressBinding soapAddressBinding = CreateSoapAddressBinding(version, wsdlPort);
54 return soapAddressBinding;
57 internal static WsdlNS.SoapBinding GetOrCreateSoapBinding(WsdlEndpointConversionContext endpointContext, WsdlExporter exporter)
59 if (GetSoapVersionState(endpointContext.WsdlBinding, exporter) == EnvelopeVersion.None)
62 WsdlNS.SoapBinding existingSoapBinding = GetSoapBinding(endpointContext);
63 if (existingSoapBinding != null)
65 return existingSoapBinding;
68 EnvelopeVersion version = GetSoapVersion(endpointContext.WsdlBinding);
69 WsdlNS.SoapBinding soapBinding = CreateSoapBinding(version, endpointContext.WsdlBinding);
73 internal static WsdlNS.SoapOperationBinding GetOrCreateSoapOperationBinding(WsdlEndpointConversionContext endpointContext, OperationDescription operation, WsdlExporter exporter)
75 if (GetSoapVersionState(endpointContext.WsdlBinding, exporter) == EnvelopeVersion.None)
78 WsdlNS.SoapOperationBinding existingSoapOperationBinding = GetSoapOperationBinding(endpointContext, operation);
79 WsdlNS.OperationBinding wsdlOperationBinding = endpointContext.GetOperationBinding(operation);
80 EnvelopeVersion version = GetSoapVersion(endpointContext.WsdlBinding);
82 if (existingSoapOperationBinding != null)
83 return existingSoapOperationBinding;
85 WsdlNS.SoapOperationBinding soapOperationBinding = CreateSoapOperationBinding(version, wsdlOperationBinding);
86 return soapOperationBinding;
89 internal static WsdlNS.SoapBodyBinding GetOrCreateSoapBodyBinding(WsdlEndpointConversionContext endpointContext, WsdlNS.MessageBinding wsdlMessageBinding, WsdlExporter exporter)
91 if (GetSoapVersionState(endpointContext.WsdlBinding, exporter) == EnvelopeVersion.None)
94 WsdlNS.SoapBodyBinding existingSoapBodyBinding = GetSoapBodyBinding(endpointContext, wsdlMessageBinding);
95 EnvelopeVersion version = GetSoapVersion(endpointContext.WsdlBinding);
97 if (existingSoapBodyBinding != null)
98 return existingSoapBodyBinding;
100 WsdlNS.SoapBodyBinding soapBodyBinding = CreateSoapBodyBinding(version, wsdlMessageBinding);
101 return soapBodyBinding;
104 internal static WsdlNS.SoapHeaderBinding CreateSoapHeaderBinding(WsdlEndpointConversionContext endpointContext, WsdlNS.MessageBinding wsdlMessageBinding)
106 EnvelopeVersion version = GetSoapVersion(endpointContext.WsdlBinding);
108 WsdlNS.SoapHeaderBinding soapHeaderBinding = CreateSoapHeaderBinding(version, wsdlMessageBinding);
109 return soapHeaderBinding;
112 internal static void CreateSoapFaultBinding(string name, WsdlEndpointConversionContext endpointContext, WsdlNS.FaultBinding wsdlFaultBinding, bool isEncoded)
114 EnvelopeVersion version = GetSoapVersion(endpointContext.WsdlBinding);
115 XmlElement fault = CreateSoapFaultBinding(version);
116 fault.Attributes.Append(CreateLocalAttribute("name", name));
117 fault.Attributes.Append(CreateLocalAttribute("use", isEncoded ? "encoded" : "literal"));
118 wsdlFaultBinding.Extensions.Add(fault);
121 internal static void SetSoapVersion(WsdlEndpointConversionContext endpointContext, WsdlExporter exporter, EnvelopeVersion version)
123 SetSoapVersionState(endpointContext.WsdlBinding, exporter, version);
125 //Convert all SOAP extensions to the right version.
126 if (endpointContext.WsdlPort != null)
127 SoapConverter.ConvertExtensions(endpointContext.WsdlPort.Extensions, version, SoapConverter.ConvertSoapAddressBinding);
129 SoapConverter.ConvertExtensions(endpointContext.WsdlBinding.Extensions, version, SoapConverter.ConvertSoapBinding);
131 foreach (WsdlNS.OperationBinding operationBinding in endpointContext.WsdlBinding.Operations)
133 SoapConverter.ConvertExtensions(operationBinding.Extensions, version, SoapConverter.ConvertSoapOperationBinding);
137 if (operationBinding.Input != null)
138 SoapConverter.ConvertExtensions(operationBinding.Input.Extensions, version, SoapConverter.ConvertSoapMessageBinding);
139 if (operationBinding.Output != null)
140 SoapConverter.ConvertExtensions(operationBinding.Output.Extensions, version, SoapConverter.ConvertSoapMessageBinding);
142 foreach (WsdlNS.MessageBinding faultBinding in operationBinding.Faults)
143 SoapConverter.ConvertExtensions(faultBinding.Extensions, version, SoapConverter.ConvertSoapMessageBinding);
149 internal static EnvelopeVersion GetSoapVersion(WsdlNS.Binding wsdlBinding)
151 foreach (object o in wsdlBinding.Extensions)
153 if (o is WsdlNS.SoapBinding)
154 return o is WsdlNS.Soap12Binding ? EnvelopeVersion.Soap12 : EnvelopeVersion.Soap11;
156 return EnvelopeVersion.Soap12;
159 private static void SetSoapVersionState(WsdlNS.Binding wsdlBinding, WsdlExporter exporter, EnvelopeVersion version)
161 object versions = null;
163 if (!exporter.State.TryGetValue(SoapVersionStateKey, out versions))
165 versions = new Dictionary<WsdlNS.Binding, EnvelopeVersion>();
166 exporter.State[SoapVersionStateKey] = versions;
169 ((Dictionary<WsdlNS.Binding, EnvelopeVersion>)versions)[wsdlBinding] = version;
172 private static EnvelopeVersion GetSoapVersionState(WsdlNS.Binding wsdlBinding, WsdlExporter exporter)
174 object versions = null;
176 if (exporter.State.TryGetValue(SoapVersionStateKey, out versions))
178 if (versions != null && ((Dictionary<WsdlNS.Binding, EnvelopeVersion>)versions).ContainsKey(wsdlBinding))
180 return ((Dictionary<WsdlNS.Binding, EnvelopeVersion>)versions)[wsdlBinding];
186 static class SoapConverter
189 // Microsoft, this could be simplified if we used generics.
190 internal static void ConvertExtensions(WsdlNS.ServiceDescriptionFormatExtensionCollection extensions, EnvelopeVersion version, ConvertExtension conversionMethod)
192 bool foundOne = false;
193 for (int i = extensions.Count - 1; i >= 0; i--)
195 object o = extensions[i];
196 if (conversionMethod(ref o, version))
199 extensions.Remove(extensions[i]);
209 conversionMethod(ref o, version);
216 // This is the delegate implemented by the 4 methods below. It is expected to:
217 // If given a null reference for src, a new instance of the extension can be set.
218 internal delegate bool ConvertExtension(ref object src, EnvelopeVersion version);
220 internal static bool ConvertSoapBinding(ref object src, EnvelopeVersion version)
222 WsdlNS.SoapBinding binding = src as WsdlNS.SoapBinding;
227 return false; // not a soap object
228 else if (GetBindingVersion<WsdlNS.Soap12Binding>(src) == version)
229 return true; // matched but same version; no change
232 if (version == EnvelopeVersion.None)
238 WsdlNS.SoapBinding dest = version == EnvelopeVersion.Soap12 ? new WsdlNS.Soap12Binding() : new WsdlNS.SoapBinding();
241 dest.Required = binding.Required;
242 dest.Style = binding.Style;
243 dest.Transport = binding.Transport;
250 internal static bool ConvertSoapAddressBinding(ref object src, EnvelopeVersion version)
252 WsdlNS.SoapAddressBinding binding = src as WsdlNS.SoapAddressBinding;
257 return false; // no match
258 else if (GetBindingVersion<WsdlNS.Soap12AddressBinding>(src) == version)
259 return true; // matched but same version; no change
262 if (version == EnvelopeVersion.None)
268 WsdlNS.SoapAddressBinding dest = version == EnvelopeVersion.Soap12 ? new WsdlNS.Soap12AddressBinding() : new WsdlNS.SoapAddressBinding();
271 dest.Required = binding.Required;
272 dest.Location = binding.Location;
280 // returns true if src is an expected type; updates src in place; should handle null
281 internal static bool ConvertSoapOperationBinding(ref object src, EnvelopeVersion version)
283 WsdlNS.SoapOperationBinding binding = src as WsdlNS.SoapOperationBinding;
288 return false; // no match
289 else if (GetBindingVersion<WsdlNS.Soap12OperationBinding>(src) == version)
290 return true; // matched but same version
293 if (version == EnvelopeVersion.None)
299 WsdlNS.SoapOperationBinding dest = version == EnvelopeVersion.Soap12 ? new WsdlNS.Soap12OperationBinding() : new WsdlNS.SoapOperationBinding();
302 dest.Required = binding.Required;
303 dest.Style = binding.Style;
304 dest.SoapAction = binding.SoapAction;
311 internal static bool ConvertSoapMessageBinding(ref object src, EnvelopeVersion version)
313 WsdlNS.SoapBodyBinding body = src as WsdlNS.SoapBodyBinding;
316 src = ConvertSoapBodyBinding(body, version);
320 WsdlNS.SoapHeaderBinding header = src as WsdlNS.SoapHeaderBinding;
323 src = ConvertSoapHeaderBinding(header, version);
327 WsdlNS.SoapFaultBinding fault = src as WsdlNS.SoapFaultBinding;
330 src = ConvertSoapFaultBinding(fault, version);
334 XmlElement element = src as XmlElement;
337 if (IsSoapFaultBinding(element))
339 src = ConvertSoapFaultBinding(element, version);
344 return src == null; // "match" only if nothing passed in
347 static WsdlNS.SoapBodyBinding ConvertSoapBodyBinding(WsdlNS.SoapBodyBinding src, EnvelopeVersion version)
349 if (version == EnvelopeVersion.None)
352 EnvelopeVersion srcVersion = GetBindingVersion<WsdlNS.Soap12BodyBinding>(src);
353 if (srcVersion == version)
356 WsdlNS.SoapBodyBinding dest = version == EnvelopeVersion.Soap12 ? new WsdlNS.Soap12BodyBinding() : new WsdlNS.SoapBodyBinding();
359 if (XmlSerializerOperationFormatter.GetEncoding(srcVersion) == src.Encoding)
360 dest.Encoding = XmlSerializerOperationFormatter.GetEncoding(version);
361 dest.Encoding = XmlSerializerOperationFormatter.GetEncoding(version);
362 dest.Namespace = src.Namespace;
363 dest.Parts = src.Parts;
364 dest.PartsString = src.PartsString;
366 dest.Required = src.Required;
371 static XmlElement ConvertSoapFaultBinding(XmlElement src, EnvelopeVersion version)
376 if (version == EnvelopeVersion.Soap12)
378 if (src.NamespaceURI == WsdlNS.Soap12Binding.Namespace)
381 else if (version == EnvelopeVersion.Soap11)
383 if (src.NamespaceURI == WsdlNS.SoapBinding.Namespace)
391 XmlElement dest = CreateSoapFaultBinding(version);
392 if (src.HasAttributes)
394 foreach (XmlAttribute attribute in src.Attributes)
396 dest.SetAttribute(attribute.Name, attribute.Value);
402 static WsdlNS.SoapFaultBinding ConvertSoapFaultBinding(WsdlNS.SoapFaultBinding src, EnvelopeVersion version)
404 if (version == EnvelopeVersion.None)
407 if (GetBindingVersion<WsdlNS.Soap12FaultBinding>(src) == version)
410 WsdlNS.SoapFaultBinding dest = version == EnvelopeVersion.Soap12 ? new WsdlNS.Soap12FaultBinding() : new WsdlNS.SoapFaultBinding();
413 dest.Encoding = src.Encoding;
414 dest.Name = src.Name;
415 dest.Namespace = src.Namespace;
417 dest.Required = src.Required;
422 static WsdlNS.SoapHeaderBinding ConvertSoapHeaderBinding(WsdlNS.SoapHeaderBinding src, EnvelopeVersion version)
424 if (version == EnvelopeVersion.None)
427 if (GetBindingVersion<WsdlNS.Soap12HeaderBinding>(src) == version)
430 WsdlNS.SoapHeaderBinding dest = version == EnvelopeVersion.Soap12 ? new WsdlNS.Soap12HeaderBinding() : new WsdlNS.SoapHeaderBinding();
433 dest.Fault = src.Fault;
434 dest.MapToProperty = src.MapToProperty;
435 dest.Message = src.Message;
436 dest.Part = src.Part;
437 dest.Encoding = src.Encoding;
438 dest.Namespace = src.Namespace;
440 dest.Required = src.Required;
445 internal static EnvelopeVersion GetBindingVersion<T12>(object src)
447 return src is T12 ? EnvelopeVersion.Soap12 : EnvelopeVersion.Soap11;
452 static WsdlNS.SoapAddressBinding CreateSoapAddressBinding(EnvelopeVersion version, WsdlNS.Port wsdlPort)
454 WsdlNS.SoapAddressBinding soapAddressBinding = null;
456 if (version == EnvelopeVersion.Soap12)
458 soapAddressBinding = new WsdlNS.Soap12AddressBinding();
460 else if (version == EnvelopeVersion.Soap11)
462 soapAddressBinding = new WsdlNS.SoapAddressBinding();
464 Fx.Assert(soapAddressBinding != null, "EnvelopeVersion is not recognized. Please update the SoapHelper class");
466 wsdlPort.Extensions.Add(soapAddressBinding);
467 return soapAddressBinding;
471 static WsdlNS.SoapBinding CreateSoapBinding(EnvelopeVersion version, WsdlNS.Binding wsdlBinding)
473 WsdlNS.SoapBinding soapBinding = null;
475 if (version == EnvelopeVersion.Soap12)
477 soapBinding = new WsdlNS.Soap12Binding();
479 else if (version == EnvelopeVersion.Soap11)
481 soapBinding = new WsdlNS.SoapBinding();
483 Fx.Assert(soapBinding != null, "EnvelopeVersion is not recognized. Please update the SoapHelper class");
485 wsdlBinding.Extensions.Add(soapBinding);
489 static WsdlNS.SoapOperationBinding CreateSoapOperationBinding(EnvelopeVersion version, WsdlNS.OperationBinding wsdlOperationBinding)
491 WsdlNS.SoapOperationBinding soapOperationBinding = null;
493 if (version == EnvelopeVersion.Soap12)
495 soapOperationBinding = new WsdlNS.Soap12OperationBinding();
497 else if (version == EnvelopeVersion.Soap11)
499 soapOperationBinding = new WsdlNS.SoapOperationBinding();
501 Fx.Assert(soapOperationBinding != null, "EnvelopeVersion is not recognized. Please update the SoapHelper class");
503 wsdlOperationBinding.Extensions.Add(soapOperationBinding);
504 return soapOperationBinding;
507 static WsdlNS.SoapBodyBinding CreateSoapBodyBinding(EnvelopeVersion version, WsdlNS.MessageBinding wsdlMessageBinding)
509 WsdlNS.SoapBodyBinding soapBodyBinding = null;
511 if (version == EnvelopeVersion.Soap12)
513 soapBodyBinding = new WsdlNS.Soap12BodyBinding();
515 else if (version == EnvelopeVersion.Soap11)
517 soapBodyBinding = new WsdlNS.SoapBodyBinding();
519 Fx.Assert(soapBodyBinding != null, "EnvelopeVersion is not recognized. Please update the SoapHelper class");
521 wsdlMessageBinding.Extensions.Add(soapBodyBinding);
522 return soapBodyBinding;
525 static WsdlNS.SoapHeaderBinding CreateSoapHeaderBinding(EnvelopeVersion version, WsdlNS.MessageBinding wsdlMessageBinding)
527 WsdlNS.SoapHeaderBinding soapHeaderBinding = null;
529 if (version == EnvelopeVersion.Soap12)
531 soapHeaderBinding = new WsdlNS.Soap12HeaderBinding();
533 else if (version == EnvelopeVersion.Soap11)
535 soapHeaderBinding = new WsdlNS.SoapHeaderBinding();
537 Fx.Assert(soapHeaderBinding != null, "EnvelopeVersion is not recognized. Please update the SoapHelper class");
539 wsdlMessageBinding.Extensions.Add(soapHeaderBinding);
540 return soapHeaderBinding;
543 static XmlElement CreateSoapFaultBinding(EnvelopeVersion version)
545 string prefix = null;
547 if (version == EnvelopeVersion.Soap12)
549 ns = WsdlNS.Soap12Binding.Namespace;
552 else if (version == EnvelopeVersion.Soap11)
554 ns = WsdlNS.SoapBinding.Namespace;
557 Fx.Assert(ns != null, "EnvelopeVersion is not recognized. Please update the SoapHelper class");
558 return Document.CreateElement(prefix, "fault", ns);
562 internal static WsdlNS.SoapAddressBinding GetSoapAddressBinding(WsdlNS.Port wsdlPort)
564 foreach (object o in wsdlPort.Extensions)
566 if (o is WsdlNS.SoapAddressBinding)
567 return (WsdlNS.SoapAddressBinding)o;
571 static WsdlNS.SoapBinding GetSoapBinding(WsdlEndpointConversionContext endpointContext)
573 foreach (object o in endpointContext.WsdlBinding.Extensions)
575 if (o is WsdlNS.SoapBinding)
576 return (WsdlNS.SoapBinding)o;
581 static WsdlNS.SoapOperationBinding GetSoapOperationBinding(WsdlEndpointConversionContext endpointContext, OperationDescription operation)
583 WsdlNS.OperationBinding wsdlOperationBinding = endpointContext.GetOperationBinding(operation);
585 foreach (object o in wsdlOperationBinding.Extensions)
587 if (o is WsdlNS.SoapOperationBinding)
588 return (WsdlNS.SoapOperationBinding)o;
593 static WsdlNS.SoapBodyBinding GetSoapBodyBinding(WsdlEndpointConversionContext endpointContext, WsdlNS.MessageBinding wsdlMessageBinding)
595 foreach (object o in wsdlMessageBinding.Extensions)
597 if (o is WsdlNS.SoapBodyBinding)
598 return (WsdlNS.SoapBodyBinding)o;
603 internal static string ReadSoapAction(WsdlNS.OperationBinding wsdlOperationBinding)
605 WsdlNS.SoapOperationBinding soapOperationBinding = (WsdlNS.SoapOperationBinding)wsdlOperationBinding.Extensions.Find(typeof(WsdlNS.SoapOperationBinding));
606 return soapOperationBinding != null ? soapOperationBinding.SoapAction : null;
609 internal static WsdlNS.SoapBindingStyle GetStyle(WsdlNS.Binding binding)
611 WsdlNS.SoapBindingStyle style = WsdlNS.SoapBindingStyle.Default;
614 WsdlNS.SoapBinding soapBinding = binding.Extensions.Find(typeof(WsdlNS.SoapBinding)) as WsdlNS.SoapBinding;
615 if (soapBinding != null)
616 style = soapBinding.Style;
621 internal static WsdlNS.SoapBindingStyle GetStyle(WsdlNS.OperationBinding operationBinding, WsdlNS.SoapBindingStyle defaultBindingStyle)
623 WsdlNS.SoapBindingStyle style = defaultBindingStyle;
624 if (operationBinding != null)
626 WsdlNS.SoapOperationBinding soapOperationBinding = operationBinding.Extensions.Find(typeof(WsdlNS.SoapOperationBinding)) as WsdlNS.SoapOperationBinding;
627 if (soapOperationBinding != null)
629 if (soapOperationBinding.Style != WsdlNS.SoapBindingStyle.Default)
630 style = soapOperationBinding.Style;
636 internal static bool IsSoapFaultBinding(XmlElement element)
638 return (element != null && element.LocalName == "fault" && (element.NamespaceURI == WsdlNS.Soap12Binding.Namespace || element.NamespaceURI == WsdlNS.SoapBinding.Namespace));
641 internal static bool IsEncoded(XmlElement element)
643 Fx.Assert(element != null, "");
644 XmlAttribute attribute = element.GetAttributeNode("use");
645 if (attribute == null)
647 return attribute.Value == "encoded";