File: System\ServiceModel\Channels\MessageEncodingBindingElementImporter.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
 
namespace System.ServiceModel.Channels
{
    using System.Collections.Generic;
    using System.ServiceModel.Description;
    using System.Xml;
    using System.Xml.Schema;
    using System.Web.Services.Description;
 
    public class MessageEncodingBindingElementImporter : IWsdlImportExtension, IPolicyImportExtension
    {
 
        void IWsdlImportExtension.BeforeImport(ServiceDescriptionCollection wsdlDocuments, XmlSchemaSet xmlSchemas, ICollection<XmlElement> policy)
        {
        }
 
        void IWsdlImportExtension.ImportContract(WsdlImporter importer, WsdlContractConversionContext context) { }
        void IWsdlImportExtension.ImportEndpoint(WsdlImporter importer, WsdlEndpointConversionContext context)
        {
            if (context == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
            }
 
#pragma warning suppress 56506 // Microsoft, these properties cannot be null in this context
            if (context.Endpoint.Binding == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context.Endpoint.Binding");
            }
 
            BindingElementCollection bindingElements = GetBindingElements(context);
            MessageEncodingBindingElement messageEncodingBindingElement = bindingElements.Find<MessageEncodingBindingElement>();
            TextMessageEncodingBindingElement textEncodingBindingElement = messageEncodingBindingElement as TextMessageEncodingBindingElement;
 
            if (messageEncodingBindingElement != null)
            {
                Type elementType = messageEncodingBindingElement.GetType();
                if (elementType != typeof(TextMessageEncodingBindingElement)
                    && elementType != typeof(BinaryMessageEncodingBindingElement)
                    && elementType != typeof(MtomMessageEncodingBindingElement))
                    return;
            }
 
            EnsureMessageEncoding(context, messageEncodingBindingElement);
 
            foreach (OperationBinding wsdlOperationBinding in context.WsdlBinding.Operations)
            {
                OperationDescription operation = context.GetOperationDescription(wsdlOperationBinding);
 
                for (int i = 0; i < operation.Messages.Count; i++)
                {
                    MessageDescription message = operation.Messages[i];
                    MessageBinding wsdlMessageBinding = context.GetMessageBinding(message);
                    ImportMessageSoapAction(context.ContractConversionContext, message, wsdlMessageBinding, i != 0 /*isResponse*/);
                }
 
                foreach (FaultDescription fault in operation.Faults)
                {
                    FaultBinding wsdlFaultBinding = context.GetFaultBinding(fault);
                    if (wsdlFaultBinding != null)
                    {
                        ImportFaultSoapAction(context.ContractConversionContext, fault, wsdlFaultBinding);
                    }
                }
            }
 
        }
 
        static void ImportFaultSoapAction(WsdlContractConversionContext contractContext, FaultDescription fault, FaultBinding wsdlFaultBinding)
        {
            string soapAction = SoapHelper.ReadSoapAction(wsdlFaultBinding.OperationBinding);
 
            if (contractContext != null)
            {
                OperationFault wsdlOperationFault = contractContext.GetOperationFault(fault);
                string wsaAction = WsdlImporter.WSAddressingHelper.FindWsaActionAttribute(wsdlOperationFault);
                if (wsaAction == null && soapAction != null)
                    fault.Action = soapAction;
                //
 
            }
            else
            {
                //
            }
        }
 
        static void ImportMessageSoapAction(WsdlContractConversionContext contractContext, MessageDescription message, MessageBinding wsdlMessageBinding, bool isResponse)
        {
            string soapAction = SoapHelper.ReadSoapAction(wsdlMessageBinding.OperationBinding);
 
            if (contractContext != null)
            {
                OperationMessage wsdlOperationMessage = contractContext.GetOperationMessage(message);
                string wsaAction = WsdlImporter.WSAddressingHelper.FindWsaActionAttribute(wsdlOperationMessage);
                if (wsaAction == null && soapAction != null)
                {
                    if (isResponse)
                    {
                        message.Action = "*";
                    }
                    else
                    {
                        message.Action = soapAction;
                    }
                }
                //
 
            }
            else
            {
                //
            }
        }
 
        static void EnsureMessageEncoding(WsdlEndpointConversionContext context, MessageEncodingBindingElement encodingBindingElement)
        {
            EnvelopeVersion soapVersion = SoapHelper.GetSoapVersion(context.WsdlBinding);
            AddressingVersion addressingVersion;
 
            if (encodingBindingElement == null)
            {
                encodingBindingElement = new TextMessageEncodingBindingElement();
                ConvertToCustomBinding(context).Elements.Add(encodingBindingElement);
 
                addressingVersion = AddressingVersion.None;
            }
            else
            {
                if (soapVersion == EnvelopeVersion.None)
                    addressingVersion = AddressingVersion.None;
                else
                    addressingVersion = encodingBindingElement.MessageVersion.Addressing;
            }
 
            MessageVersion newMessageVersion = MessageVersion.CreateVersion(soapVersion, addressingVersion);
            if (!encodingBindingElement.MessageVersion.IsMatch(newMessageVersion))
            {
                ConvertToCustomBinding(context).Elements.Find<MessageEncodingBindingElement>().MessageVersion
                    = MessageVersion.CreateVersion(soapVersion, addressingVersion);
            }
        }
 
        static BindingElementCollection GetBindingElements(WsdlEndpointConversionContext context)
        {
            Binding binding = context.Endpoint.Binding;
            BindingElementCollection elements = binding is CustomBinding ? ((CustomBinding)binding).Elements : binding.CreateBindingElements();
            return elements;
        }
 
        static CustomBinding ConvertToCustomBinding(WsdlEndpointConversionContext context)
        {
            CustomBinding customBinding = context.Endpoint.Binding as CustomBinding;
            if (customBinding == null)
            {
                customBinding = new CustomBinding(context.Endpoint.Binding);
                context.Endpoint.Binding = customBinding;
            }
            return customBinding;
        }
 
 
        void IPolicyImportExtension.ImportPolicy(MetadataImporter importer, PolicyConversionContext context)
        {
            if (importer == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("importer");
            }
 
            if (context == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("context");
            }
 
            ImportPolicyInternal(context);
        }
 
        void ImportPolicyInternal(PolicyConversionContext context)
        {
            ICollection<XmlElement> assertions = context.GetBindingAssertions();
 
            XmlElement encodingAssertion;
            MessageEncodingBindingElement encodingBindingElement;
            encodingBindingElement = CreateEncodingBindingElement(context.GetBindingAssertions(), out encodingAssertion);
 
            AddressingVersion addressingVersion = WsdlImporter.WSAddressingHelper.FindAddressingVersion(context);
            ApplyAddressingVersion(encodingBindingElement, addressingVersion);
 
 
#pragma warning suppress 56506
            context.BindingElements.Add(encodingBindingElement);
        }
 
        static void ApplyAddressingVersion(MessageEncodingBindingElement encodingBindingElement, AddressingVersion addressingVersion)
        {
            EnvelopeVersion defaultEnvelopeVersion = encodingBindingElement.MessageVersion.Envelope;
 
            if (defaultEnvelopeVersion == EnvelopeVersion.None
                && addressingVersion != AddressingVersion.None)
            {
                // The default envelope version is None which incompatible with the 
                // addressing version.
                // We replace it with soap12. This will be updated at wsdl import time if necessary.
                encodingBindingElement.MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, addressingVersion);
            }
            else
            {
                encodingBindingElement.MessageVersion = MessageVersion.CreateVersion(defaultEnvelopeVersion, addressingVersion);
            }
        }
 
        MessageEncodingBindingElement CreateEncodingBindingElement(ICollection<XmlElement> assertions, out XmlElement encodingAssertion)
        {
            encodingAssertion = null;
            foreach (XmlElement assertion in assertions)
            {
                switch (assertion.NamespaceURI)
                {
                    case MessageEncodingPolicyConstants.BinaryEncodingNamespace:
                        if (assertion.LocalName == MessageEncodingPolicyConstants.BinaryEncodingName)
                        {
                            encodingAssertion = assertion;
                            assertions.Remove(encodingAssertion);
                            return new BinaryMessageEncodingBindingElement();
                        }
                        break;
                    case MessageEncodingPolicyConstants.OptimizedMimeSerializationNamespace:
                        if (assertion.LocalName == MessageEncodingPolicyConstants.MtomEncodingName)
                        {
                            encodingAssertion = assertion;
                            assertions.Remove(encodingAssertion);
                            return new MtomMessageEncodingBindingElement();
                        }
                        break;
                }
            }
 
            return new TextMessageEncodingBindingElement();
        }
    }
 
    static class MessageEncodingPolicyConstants
    {
        public const string BinaryEncodingName = "BinaryEncoding";
        public const string BinaryEncodingNamespace = "http://schemas.microsoft.com/ws/06/2004/mspolicy/netbinary1";
        public const string BinaryEncodingPrefix = "msb";
        public const string OptimizedMimeSerializationNamespace = "http://schemas.xmlsoap.org/ws/2004/09/policy/optimizedmimeserialization";
        public const string OptimizedMimeSerializationPrefix = "wsoma";
        public const string MtomEncodingName = "OptimizedMimeSerialization";
    }
}