File: System\Web\Services\Description\Soap12ProtocolReflector.cs
Project: ndp\cdf\src\NetFx20\System.Web.Services\System.Web.Services.csproj (System.Web.Services)
//------------------------------------------------------------------------------
// <copyright file="Soap12ProtocolReflector.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Web.Services.Description {
 
    using System.Web.Services;
    using System.Web.Services.Protocols;
    using System.Xml;
    using System.Xml.Serialization;
    using System.Xml.Schema;
    using System.Collections;
    using System;
    using System.Reflection;
    using System.Web.Services.Configuration;
 
    internal class Soap12ProtocolReflector : SoapProtocolReflector {
        Hashtable requestElements;
        Hashtable actions;
        XmlQualifiedName soap11PortType;
 
        internal override WsiProfiles ConformsTo {
            get { return WsiProfiles.None; }
        }
 
        public override string ProtocolName {
            get { return "Soap12"; }
        }
 
        protected override void BeginClass() {
            requestElements = new Hashtable();
            actions = new Hashtable();
            soap11PortType = null;
            
            base.BeginClass();
        }
 
        protected override bool ReflectMethod() {
            if (base.ReflectMethod()) {
                if (Binding != null) {
                    // SoapMethod.portType tracks the first portType created for this method
                    // we want to make sure there's only one portType and set of messages per method
                    // so we delete ours if an existing portType already exists for this method.
                    soap11PortType = SoapMethod.portType;
                    if (soap11PortType != Binding.Type)
                        HeaderMessages.Clear();
                }
                return true;
            }
            return false;
        }
 
        protected override void EndClass() {
            if (PortType == null || Binding == null) return; // external binding;
            
            if (soap11PortType != null && soap11PortType != Binding.Type) {
                // we want to share soap 1.1's portType and messages so we delete ours and reference theirs
                foreach (Operation op in PortType.Operations) {
                    foreach (OperationMessage msg in op.Messages) {
                        ServiceDescription sd = GetServiceDescription(msg.Message.Namespace);
                        if (sd != null) {
                            Message m = sd.Messages[msg.Message.Name];
                            if (m != null)
                                sd.Messages.Remove(m);
                        }
                    }
                }
 
                Binding.Type = soap11PortType;
                PortType.ServiceDescription.PortTypes.Remove(PortType);
            }
        }
 
        protected override SoapBinding CreateSoapBinding(SoapBindingStyle style) {
            Soap12Binding soapBinding = new Soap12Binding();
            soapBinding.Transport = Soap12Binding.HttpTransport;
            soapBinding.Style = style;
            return soapBinding;
        }
 
        protected override SoapAddressBinding CreateSoapAddressBinding(string serviceUrl) {
            Soap12AddressBinding soapAddress = new Soap12AddressBinding();
            soapAddress.Location = serviceUrl;
            if (this.UriFixups != null)
            {
                this.UriFixups.Add(delegate(Uri current)
                {
                    soapAddress.Location = DiscoveryServerType.CombineUris(current, soapAddress.Location);
                });
            }
            return soapAddress;
        }
 
        protected override SoapOperationBinding CreateSoapOperationBinding(SoapBindingStyle style, string action) {
            Soap12OperationBinding soapOperation = new Soap12OperationBinding();
            soapOperation.SoapAction = action;
            soapOperation.Style = style;
            soapOperation.Method = SoapMethod;
 
            DealWithAmbiguity(action, SoapMethod.requestElementName.ToString(), soapOperation);
            
            return soapOperation;
        }
 
        protected override SoapBodyBinding CreateSoapBodyBinding(SoapBindingUse use, string ns) {
            Soap12BodyBinding soapBodyBinding = new Soap12BodyBinding();
            soapBodyBinding.Use = use;
            if (use == SoapBindingUse.Encoded)
                soapBodyBinding.Encoding = Soap12.Encoding;
            soapBodyBinding.Namespace = ns;
            return soapBodyBinding;
        }
 
        protected override SoapHeaderBinding CreateSoapHeaderBinding(XmlQualifiedName message, string partName, SoapBindingUse use) {
            return CreateSoapHeaderBinding(message, partName, null, use);
        }
 
        protected override SoapHeaderBinding CreateSoapHeaderBinding(XmlQualifiedName message, string partName, string ns, SoapBindingUse use) {
            Soap12HeaderBinding soapHeaderBinding = new Soap12HeaderBinding();
            soapHeaderBinding.Message = message;
            soapHeaderBinding.Part = partName;
            soapHeaderBinding.Namespace = ns;
            soapHeaderBinding.Use = use;
            if (use == SoapBindingUse.Encoded)
                soapHeaderBinding.Encoding = Soap12.Encoding;
            return soapHeaderBinding;
        }
 
        private void DealWithAmbiguity(string action, string requestElement, Soap12OperationBinding operation) {
 
            Soap12OperationBinding duplicateActionOperation = (Soap12OperationBinding)actions[action];
            if (duplicateActionOperation != null) {
                operation.DuplicateBySoapAction = duplicateActionOperation;
                duplicateActionOperation.DuplicateBySoapAction = operation;
                CheckOperationDuplicates(duplicateActionOperation);
            }
            else
                actions[action] = operation;
 
            Soap12OperationBinding duplicateRequestElementOperation = (Soap12OperationBinding)requestElements[requestElement];
            if (duplicateRequestElementOperation != null) {
                operation.DuplicateByRequestElement = duplicateRequestElementOperation;
                duplicateRequestElementOperation.DuplicateByRequestElement = operation;
                CheckOperationDuplicates(duplicateRequestElementOperation);
            }
            else
                requestElements[requestElement] = operation;
 
            CheckOperationDuplicates(operation);
        }
 
        private void CheckOperationDuplicates(Soap12OperationBinding operation) {
            // we require soap action if we can't route on request element 
            if (operation.DuplicateByRequestElement != null) {
                // except if we also can't route on soap action, which is an error
                if (operation.DuplicateBySoapAction != null)
                    throw new InvalidOperationException(Res.GetString(Res.TheMethodsAndUseTheSameRequestElementAndSoapActionXmlns6, operation.Method.name, operation.DuplicateByRequestElement.Method.name, operation.Method.requestElementName.Name, operation.Method.requestElementName.Namespace, operation.DuplicateBySoapAction.Method.name, operation.Method.action));
                else
                    operation.SoapActionRequired = true;
            }
            else
                operation.SoapActionRequired = false;
        }
    }
}