TypeLoader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Description / TypeLoader.cs / 2 / TypeLoader.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------

namespace System.ServiceModel.Description 
{
    using System; 
    using System.ServiceModel.Channels; 
    using System.ServiceModel.Dispatcher;
    using System.ServiceModel; 
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.Reflection; 
    using System.Xml;
    using System.Runtime.Serialization; 
    using System.Diagnostics; 

    class TypeLoader 
    {
        static Type[] messageContractMemberAttributes = {
            typeof(MessageHeaderAttribute),
            typeof(MessageBodyMemberAttribute), 
            typeof(MessagePropertyAttribute),
        }; 
 
        static Type[] formatterAttributes = {
            typeof(XmlSerializerFormatAttribute), 
            typeof(DataContractFormatAttribute)
        };

        static Type[] knownTypesMethodParamType = new Type[] { typeof(ICustomAttributeProvider) }; 

        internal static DataContractFormatAttribute DefaultDataContractFormatAttribute = new DataContractFormatAttribute(); 
        internal static XmlSerializerFormatAttribute DefaultXmlSerializerFormatAttribute = new XmlSerializerFormatAttribute(); 

        const string ReturnSuffix = "Result"; 
        const string ResponseSuffix = "Response";
        const string FaultSuffix = "Fault";
        internal const BindingFlags DefaultBindingFlags = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public;
 
        readonly object thisLock;
        readonly Dictionary contracts; 
        readonly Dictionary messages; 

        public TypeLoader() 
        {
            this.thisLock = new object();
            this.contracts = new Dictionary();
            this.messages = new Dictionary(); 
        }
 
        ContractDescription LoadContractDescriptionHelper(Type contractType, Type serviceType, object serviceImplementation) 
        {
            ContractDescription contractDescription; 
            if (contractType == typeof(IOutputChannel))
            {
                contractDescription = LoadOutputChannelContractDescription();
            } 
            else if (contractType == typeof(IRequestChannel))
            { 
                contractDescription = LoadRequestChannelContractDescription(); 
            }
            else 
            {
                ServiceContractAttribute actualContractAttribute;
                Type actualContractType = ServiceReflector.GetContractTypeAndAttribute(contractType, out actualContractAttribute);
                lock (this.thisLock) 
                {
                    if (!contracts.TryGetValue(actualContractType, out contractDescription)) 
                    { 
                        EnsureNoInheritanceWithContractClasses(actualContractType);
                        EnsureNoOperationContractsOnNonServiceContractTypes(actualContractType); 
                        ContractReflectionInfo reflectionInfo;
                        contractDescription = CreateContractDescription(actualContractAttribute, actualContractType, serviceType, out reflectionInfo, serviceImplementation);
                        // IContractBehaviors
                        if (serviceImplementation != null  &&  serviceImplementation is IContractBehavior) 
                        {
                            contractDescription.Behaviors.Add((IContractBehavior)serviceImplementation); 
                        } 
                        if (serviceType != null)
                        { 
                            UpdateContractDescriptionWithAttributesFromServiceType(contractDescription, serviceType);
                            foreach (ContractDescription inheritedContract in contractDescription.GetInheritedContracts())
                            {
                                UpdateContractDescriptionWithAttributesFromServiceType(inheritedContract, serviceType); 
                            }
                        } 
                        UpdateOperationsWithInterfaceAttributes(contractDescription, reflectionInfo); 
                        AddBehaviors(contractDescription, serviceType, false, reflectionInfo);
 
                        this.contracts.Add(actualContractType, contractDescription);
                    }
                }
            } 
            return contractDescription;
        } 
 
        void EnsureNoInheritanceWithContractClasses(Type actualContractType)
        { 
            if (actualContractType.IsClass)
            {
                // we only need to check base _classes_ here, the check for interfaces happens elsewhere
                for (Type service = actualContractType.BaseType; service != null; service = service.BaseType) 
                {
                    if (ServiceReflector.GetSingleAttribute(service) != null) 
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                            SR.GetString(SR.SFxContractInheritanceRequiresInterfaces, actualContractType, service))); 
                    }
                }
            }
        } 

        void EnsureNoOperationContractsOnNonServiceContractTypes(Type actualContractType) 
        { 
            foreach (Type t in actualContractType.GetInterfaces())
            { 
                EnsureNoOperationContractsOnNonServiceContractTypes_Helper(t);
            }
            for (Type u = actualContractType.BaseType; u != null; u = u.BaseType)
            { 
                EnsureNoOperationContractsOnNonServiceContractTypes_Helper(u);
            } 
        } 

        void EnsureNoOperationContractsOnNonServiceContractTypes_Helper(Type aParentType) 
        {
            // if not [ServiceContract]
            if (ServiceReflector.GetSingleAttribute(aParentType) == null)
            { 
                foreach (MethodInfo methodInfo in aParentType.GetMethods(DefaultBindingFlags))
                { 
                    // but does have [OperationContract] 
                    if (ServiceReflector.GetSingleAttribute(methodInfo) != null)
                    { 
                        // throw
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(
                            SR.SFxOperationContractOnNonServiceContract, methodInfo.Name, aParentType.Name)));
                    } 
                }
            } 
        } 

        public ContractDescription LoadContractDescription(Type contractType) 
        {
            DiagnosticUtility.DebugAssert(contractType != null, "");

            return LoadContractDescriptionHelper(contractType, null, null); 
        }
 
        public ContractDescription LoadContractDescription(Type contractType, Type serviceType) 
        {
            DiagnosticUtility.DebugAssert(contractType != null, ""); 
            DiagnosticUtility.DebugAssert(serviceType != null, "");

            return LoadContractDescriptionHelper(contractType, serviceType, null);
        } 

        public ContractDescription LoadContractDescription(Type contractType, Type serviceType, object serviceImplementation) 
        { 
            DiagnosticUtility.DebugAssert(contractType != null, "");
            DiagnosticUtility.DebugAssert(serviceType != null, ""); 
            DiagnosticUtility.DebugAssert(serviceImplementation != null, "");

            return LoadContractDescriptionHelper(contractType, serviceType, serviceImplementation);
        } 

        ContractDescription LoadOutputChannelContractDescription() 
        { 
            Type channelType = typeof(IOutputChannel);
            XmlQualifiedName contractName = NamingHelper.GetContractName(channelType, null, NamingHelper.MSNamespace); 
            ContractDescription contract = new ContractDescription(contractName.Name, contractName.Namespace);
            contract.ContractType = channelType;
            contract.ConfigurationName = channelType.FullName;
            contract.SessionMode = SessionMode.NotAllowed; 
            OperationDescription operation = new OperationDescription("Send", contract);
            MessageDescription message = new MessageDescription(MessageHeaders.WildcardAction, MessageDirection.Input); 
            operation.Messages.Add(message); 
            contract.Operations.Add(operation);
            return contract; 
        }

        ContractDescription LoadRequestChannelContractDescription()
        { 
            Type channelType = typeof(IRequestChannel);
            XmlQualifiedName contractName = NamingHelper.GetContractName(channelType, null, NamingHelper.MSNamespace); 
            ContractDescription contract = new ContractDescription(contractName.Name, contractName.Namespace); 
            contract.ContractType = channelType;
            contract.ConfigurationName = channelType.FullName; 
            contract.SessionMode = SessionMode.NotAllowed;
            OperationDescription operation = new OperationDescription("Request", contract);
            MessageDescription request = new MessageDescription(MessageHeaders.WildcardAction, MessageDirection.Input);
            MessageDescription reply = new MessageDescription(MessageHeaders.WildcardAction, MessageDirection.Output); 
            operation.Messages.Add(request);
            operation.Messages.Add(reply); 
            contract.Operations.Add(operation); 
            return contract;
        } 

        void AddBehaviors(ContractDescription contractDesc, Type implType, bool implIsCallback, ContractReflectionInfo reflectionInfo)
        {
            ServiceContractAttribute contractAttr = ServiceReflector.GetRequiredSingleAttribute(reflectionInfo.iface); 
            for (int i = 0; i < contractDesc.Operations.Count; i++)
            { 
                OperationDescription operationDescription = contractDesc.Operations[i]; 
                bool isInherited = operationDescription.DeclaringContract != contractDesc;
                if (!isInherited) 
                {
                    operationDescription.Behaviors.Add(new OperationInvokerBehavior());
                }
            } 
            contractDesc.Behaviors.Add(new OperationSelectorBehavior());
 
            for (int i = 0; i < contractDesc.Operations.Count; i++) 
            {
                OperationDescription opDesc = contractDesc.Operations[i]; 
                bool isInherited = opDesc.DeclaringContract != contractDesc;
                Type targetIface = implIsCallback ? opDesc.DeclaringContract.CallbackContractType : opDesc.DeclaringContract.ContractType;

                if (implType == null && !isInherited) 
                {
                    KeyedByTypeCollection toAdd = 
                        GetIOperationBehaviorAttributesFromType(opDesc, targetIface, null); 
                    for (int j = 0; j < toAdd.Count; j++)
                    { 
                        opDesc.Behaviors.Add(toAdd[j]);
                    }
                }
                else 
                {
                    // look for IOperationBehaviors on implementation methods in service class hierarchy 
                    ApplyServiceInheritance>( 
                        implType, opDesc.Behaviors,
                        delegate(Type currentType, KeyedByTypeCollection behaviors) { 
                            KeyedByTypeCollection toAdd =
                                GetIOperationBehaviorAttributesFromType(opDesc, targetIface, currentType);
                            for (int j = 0; j < toAdd.Count; j++)
                            { 
                                behaviors.Add(toAdd[j]);
                            } 
                        } ); 
                    // then look for IOperationBehaviors on interface type
                    if (!isInherited) 
                    {
                        AddBehaviorsAtOneScope>(
                            targetIface, opDesc.Behaviors,
                            delegate(Type currentType, KeyedByTypeCollection behaviors) { 
                                KeyedByTypeCollection toAdd =
                                    GetIOperationBehaviorAttributesFromType(opDesc, targetIface, null); 
                                for (int j = 0; j < toAdd.Count; j++) 
                                {
                                    behaviors.Add(toAdd[j]); 
                                }
                            } );
                    }
                } 
            }
 
            for (int i = 0; i < contractDesc.Operations.Count; i++) 
            {
                OperationDescription opDesc = contractDesc.Operations[i]; 
                OperationBehaviorAttribute operationBehavior = opDesc.Behaviors.Find();
                if (operationBehavior == null)
                {
                    operationBehavior = new OperationBehaviorAttribute(); 
                    opDesc.Behaviors.Add(operationBehavior);
                } 
            } 

            Type targetInterface = implIsCallback ? reflectionInfo.callbackiface : reflectionInfo.iface; 
            AddBehaviorsAtOneScope>(targetInterface, contractDesc.Behaviors,
                GetIContractBehaviorsFromInterfaceType);

            bool hasXmlSerializerMethod = false; 
            for (int i = 0; i < contractDesc.Operations.Count; i++)
            { 
                OperationDescription operationDescription = contractDesc.Operations[i]; 
                bool isInherited = operationDescription.DeclaringContract != contractDesc;
                MethodInfo opMethod = operationDescription.OperationMethod; 
                Attribute formattingAttribute = GetFormattingAttribute(opMethod,
                                                    GetFormattingAttribute(operationDescription.DeclaringContract.ContractType,
                                                        DefaultDataContractFormatAttribute));
                DataContractFormatAttribute dataContractFormatAttribute = formattingAttribute as DataContractFormatAttribute; 
                if (dataContractFormatAttribute != null)
                { 
                    if (!isInherited) 
                    {
                        operationDescription.Behaviors.Add(new DataContractSerializerOperationBehavior(operationDescription, dataContractFormatAttribute, true)); 
                        operationDescription.Behaviors.Add(new DataContractSerializerOperationGenerator());
                    }
                }
                else if (formattingAttribute != null && formattingAttribute is XmlSerializerFormatAttribute) 
                {
                    hasXmlSerializerMethod = true; 
                } 
            }
            if (hasXmlSerializerMethod) 
            {
                XmlSerializerOperationBehavior.AddBuiltInBehaviors(contractDesc);
            }
        } 

        void GetIContractBehaviorsFromInterfaceType(Type interfaceType, KeyedByTypeCollection behaviors) 
        { 
            object[] ifaceAttributes = ServiceReflector.GetCustomAttributes(interfaceType, typeof(IContractBehavior), false);
            for (int i = 0; i < ifaceAttributes.Length; i++) 
            {
                IContractBehavior behavior = (IContractBehavior) ifaceAttributes[i];
                behaviors.Add(behavior);
            } 
        }
 
        static void UpdateContractDescriptionWithAttributesFromServiceType(ContractDescription description, Type serviceType) 
        {
            ApplyServiceInheritance>( 
                serviceType, description.Behaviors,
                delegate(Type currentType, KeyedByTypeCollection behaviors) {

                    foreach (IContractBehavior iContractBehavior in ServiceReflector.GetCustomAttributes(currentType, typeof(IContractBehavior), false)) 
                    {
                        IContractBehaviorAttribute iContractBehaviorAttribute = iContractBehavior as IContractBehaviorAttribute; 
                        if (iContractBehaviorAttribute == null 
                            || (iContractBehaviorAttribute.TargetContract == null)
                            || (iContractBehaviorAttribute.TargetContract == description.ContractType)) 
                        {
                            behaviors.Add(iContractBehavior);
                        }
                    } 
                } );
        } 
 
        void UpdateOperationsWithInterfaceAttributes(ContractDescription contractDesc, ContractReflectionInfo reflectionInfo)
        { 
            object[] customAttributes = ServiceReflector.GetCustomAttributes(reflectionInfo.iface, typeof(ServiceKnownTypeAttribute), false);
            IEnumerable knownTypes = GetKnownTypes(customAttributes, reflectionInfo.iface);
            foreach(Type knownType in knownTypes)
            { 
                foreach (OperationDescription operationDescription in contractDesc.Operations)
                { 
                    if (!operationDescription.IsServerInitiated()) 
                        operationDescription.KnownTypes.Add(knownType);
                } 
            }

            if (reflectionInfo.callbackiface != null)
            { 
                customAttributes = ServiceReflector.GetCustomAttributes(reflectionInfo.callbackiface, typeof(ServiceKnownTypeAttribute), false);
                knownTypes = GetKnownTypes(customAttributes, reflectionInfo.callbackiface); 
                foreach (Type knownType in knownTypes) 
                {
                    foreach (OperationDescription operationDescription in contractDesc.Operations) 
                    {
                        if (operationDescription.IsServerInitiated())
                            operationDescription.KnownTypes.Add(knownType);
                    } 
                }
            } 
        } 

        private IEnumerable GetKnownTypes(object[] knownTypeAttributes, ICustomAttributeProvider provider) 
        {
            if (knownTypeAttributes.Length == 1)
            {
                ServiceKnownTypeAttribute knownTypeAttribute = (ServiceKnownTypeAttribute)knownTypeAttributes[0]; 
                if (!string.IsNullOrEmpty(knownTypeAttribute.MethodName))
                { 
                    Type type = knownTypeAttribute.DeclaringType; 
                    if (type == null)
                    { 
                        type = provider as Type;
                        if (type == null)
                            type = ((MethodInfo)provider).DeclaringType;
                    } 
                    MethodInfo method = type.GetMethod(knownTypeAttribute.MethodName, BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, null, knownTypesMethodParamType, null);
                    if (method == null) 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxKnownTypeAttributeUnknownMethod3, provider, knownTypeAttribute.MethodName, type.FullName))); 

                    if (!typeof(IEnumerable).IsAssignableFrom(method.ReturnType)) 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxKnownTypeAttributeReturnType3, provider, knownTypeAttribute.MethodName, type.FullName)));

                    return (IEnumerable)method.Invoke(null, new object[] { provider });
                } 
            }
 
            List knownTypes = new List(); 
            for (int i = 0; i < knownTypeAttributes.Length; ++i)
            { 
                ServiceKnownTypeAttribute knownTypeAttribute = (ServiceKnownTypeAttribute)knownTypeAttributes[i];
                if (knownTypeAttribute.Type == null)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxKnownTypeAttributeInvalid1, provider.ToString())));
                knownTypes.Add(knownTypeAttribute.Type); 
            }
            return knownTypes; 
        } 

        KeyedByTypeCollection GetIOperationBehaviorAttributesFromType(OperationDescription opDesc, Type targetIface, Type implType) 
        {
            KeyedByTypeCollection result = new KeyedByTypeCollection();
            InterfaceMapping ifaceMap = default(InterfaceMapping);
            bool useImplAttrs = false; 
            if (implType != null)
            { 
                if (targetIface.IsAssignableFrom(implType) && targetIface.IsInterface) 
                {
                    ifaceMap = implType.GetInterfaceMap(targetIface); 
                    useImplAttrs = true;
                }
                else
                { 
                    // implType does not implement any methods from the targetIface, so there is nothing to do
                    return result; 
                } 
            }
            MethodInfo opMethod = opDesc.OperationMethod; 
            ProcessOpMethod(opMethod, true, opDesc, result, ifaceMap, useImplAttrs);
            if (opDesc.SyncMethod != null && opDesc.BeginMethod != null)
            {
                ProcessOpMethod(opDesc.BeginMethod, false, opDesc, result, ifaceMap, useImplAttrs); 
            }
            return result; 
        } 

        void ProcessOpMethod(MethodInfo opMethod, bool canHaveBehaviors, 
                             OperationDescription opDesc, KeyedByTypeCollection result,
                             InterfaceMapping ifaceMap, bool useImplAttrs)
        {
            MethodInfo method = null; 
            if (useImplAttrs)
            { 
                int methodIndex = Array.IndexOf(ifaceMap.InterfaceMethods, opMethod); 
                // if opMethod doesn't exist in the interfacemap, it means opMethod was on
                // the "other" interface (not the one implemented by implType) 
                if (methodIndex != -1)
                {
                    MethodInfo implMethod = ifaceMap.TargetMethods[methodIndex];
                    // C++ allows you to create abstract classes that have missing interface method 
                    // implementations, which shows up as nulls in the interfacemapping
                    if (implMethod != null) 
                    { 
                        method = implMethod;
                    } 
                }
                if (method == null)
                {
                    return; 
                }
            } 
            else 
            {
                method = opMethod; 
            }

            object[] methodAttributes = ServiceReflector.GetCustomAttributes(method, typeof(IOperationBehavior), false);
            for (int k = 0; k < methodAttributes.Length; k++) 
            {
                IOperationBehavior opBehaviorAttr = (IOperationBehavior)methodAttributes[k]; 
                if (canHaveBehaviors) 
                {
                    result.Add(opBehaviorAttr); 
                }
                else
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                        new InvalidOperationException(SR.GetString(SR.SyncAsyncMatchConsistency_Attributes6,
                                                                   opDesc.SyncMethod.Name, 
                                                                   opDesc.SyncMethod.DeclaringType, 
                                                                   opDesc.BeginMethod.Name,
                                                                   opDesc.EndMethod.Name, 
                                                                   opDesc.Name,
                                                                   opBehaviorAttr.GetType().FullName)));
                }
            } 
        }
 
        internal void AddBehaviorsSFx(ServiceEndpoint serviceEndpoint, Type contractType) 
        {
            if (serviceEndpoint.Contract.IsDuplex()) 
            {
                CallbackBehaviorAttribute attr = serviceEndpoint.Behaviors.Find();
                if (attr == null)
                { 
                    serviceEndpoint.Behaviors.Insert(0, new CallbackBehaviorAttribute());
                } 
            } 
        }
 
        internal void AddBehaviorsFromImplementationType(ServiceEndpoint serviceEndpoint, Type implementationType)
        {
            foreach (IEndpointBehavior behaviorAttribute in ServiceReflector.GetCustomAttributes(implementationType, typeof(IEndpointBehavior), false))
            { 
                if (behaviorAttribute is CallbackBehaviorAttribute)
                { 
                    serviceEndpoint.Behaviors.Insert(0, behaviorAttribute); 
                }
                else 
                {
                    serviceEndpoint.Behaviors.Add(behaviorAttribute);
                }
            } 
            foreach (IContractBehavior behaviorAttribute in ServiceReflector.GetCustomAttributes(implementationType, typeof(IContractBehavior), false))
            { 
                serviceEndpoint.Contract.Behaviors.Add(behaviorAttribute); 
            }
            Type targetIface = serviceEndpoint.Contract.CallbackContractType; 
            for (int i = 0; i < serviceEndpoint.Contract.Operations.Count; i++)
            {
                OperationDescription opDesc = serviceEndpoint.Contract.Operations[i];
                KeyedByTypeCollection opBehaviors = new KeyedByTypeCollection(); 
                // look for IOperationBehaviors on implementation methods in callback class hierarchy
                ApplyServiceInheritance>( 
                    implementationType, opBehaviors, 
                    delegate(Type currentType, KeyedByTypeCollection behaviors) {
                        KeyedByTypeCollection toAdd = 
                            GetIOperationBehaviorAttributesFromType(opDesc, targetIface, currentType);
                        for (int j = 0; j < toAdd.Count; j++)
                        {
                            behaviors.Add(toAdd[j]); 
                        }
                    } ); 
                // a bunch of default IOperationBehaviors have already been added, which we may need to replace 
                for (int k = 0; k < opBehaviors.Count; k++)
                { 
                    IOperationBehavior behavior = opBehaviors[k];
                    Type t = behavior.GetType();
                    if (opDesc.Behaviors.Contains(t))
                    { 
                        opDesc.Behaviors.Remove(t);
                    } 
                    opDesc.Behaviors.Add(behavior); 
                }
            } 
        }

        internal static int CompareMessagePartDescriptions(MessagePartDescription a, MessagePartDescription b)
        { 
            int posCmp = a.SerializationPosition - b.SerializationPosition;
            if (posCmp != 0) 
            { 
                return posCmp;
            } 

            int nsCmp = string.Compare(a.Namespace, b.Namespace, StringComparison.Ordinal);
            if (nsCmp != 0)
            { 
                return nsCmp;
            } 
 
            return string.Compare(a.Name, b.Name, StringComparison.Ordinal);
        } 

        internal static XmlName GetBodyWrapperResponseName(string operationName)
        {
#if DEBUG 
            DiagnosticUtility.DebugAssert(NamingHelper.IsValidNCName(operationName), "operationName value has to be a valid NCName.");
#endif 
            return new XmlName(operationName + ResponseSuffix); 
        }
 
        internal static XmlName GetBodyWrapperResponseName(XmlName operationName)
        {
            return new XmlName(operationName.EncodedName + ResponseSuffix, true /*isEncoded*/);
        } 

        void CreateOperationDescriptions(ContractDescription contractDescription, 
                                         ContractReflectionInfo reflectionInfo, 
                                         Type contractToGetMethodsFrom,
                                         ContractDescription declaringContract, 
                                         MessageDirection direction
                                         )
        {
            MessageDirection otherDirection = MessageDirectionHelper.Opposite(direction); 
            if (!(declaringContract.ContractType.IsAssignableFrom(contractDescription.ContractType)))
            { 
                DiagnosticUtility.DebugAssert("bad contract inheritance"); 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                    String.Format(CultureInfo.InvariantCulture, "Bad contract inheritence. Contract {0} does not implement {1}", declaringContract.ContractType.Name , contractDescription.ContractType.Name) 
                    ));
            }

            foreach (MethodInfo methodInfo in contractToGetMethodsFrom.GetMethods(DefaultBindingFlags)) 
            {
                if (contractToGetMethodsFrom.IsInterface) 
                { 
                    object[] attrs = ServiceReflector.GetCustomAttributes(methodInfo, typeof(OperationBehaviorAttribute), false);
                    if (attrs.Length != 0) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                            SR.GetString(SR.SFxOperationBehaviorAttributeOnlyOnServiceClass, methodInfo.Name, contractToGetMethodsFrom.Name)));
                    } 
                }
                ServiceReflector.ValidateParameterMetadata(methodInfo); 
                OperationDescription operation = CreateOperationDescription(contractDescription, methodInfo, direction, reflectionInfo, declaringContract); 
                if (operation != null)
                { 
                    contractDescription.Operations.Add(operation);
                }
            }
        } 

        //Checks whether that the Callback contract provided on a ServiceContract follows rules 
        //1. It has to be a interface 
        //2. If its a class then it needs to implement MarshallByRefObject
        internal static void EnsureCallbackType(Type callbackType) 
        {
            if (callbackType != null && !callbackType.IsInterface && !callbackType.IsMarshalByRef)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.GetString(SR.SFxInvalidCallbackContractType,callbackType.Name))); 
            }
        } 
 
        // checks a contract for substitutability (in the Liskov Substitution Principle sense), throws on error
        internal static void EnsureSubcontract(ServiceContractAttribute svcContractAttr, Type contractType) 
        {
            Type callbackType = svcContractAttr.CallbackContract;

            List types = ServiceReflector.GetInheritedContractTypes(contractType); 
            for (int i = 0; i < types.Count; i++)
            { 
                Type inheritedContractType = types[i]; 
                ServiceContractAttribute inheritedContractAttr = ServiceReflector.GetRequiredSingleAttribute(inheritedContractType);
                // we must be covariant in our callbacks 
                if (inheritedContractAttr.CallbackContract != null)
                {
                    if (callbackType == null)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                            SR.GetString(SR.InAContractInheritanceHierarchyIfParentHasCallbackChildMustToo, 
                            inheritedContractType.Name, inheritedContractAttr.CallbackContract.Name, contractType.Name))); 
                    }
                    if (!inheritedContractAttr.CallbackContract.IsAssignableFrom(callbackType)) 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                            SR.GetString(SR.InAContractInheritanceHierarchyTheServiceContract3_2,
                            inheritedContractType.Name, contractType.Name))); 
                    }
                } 
            } 
        }
 
        ContractDescription CreateContractDescription(ServiceContractAttribute contractAttr, Type contractType, Type serviceType, out ContractReflectionInfo reflectionInfo, object serviceImplementation)
        {
            reflectionInfo = new ContractReflectionInfo();
 
            XmlQualifiedName contractName = NamingHelper.GetContractName(contractType, contractAttr.Name, contractAttr.Namespace);
            ContractDescription contractDescription = new ContractDescription(contractName.Name, contractName.Namespace); 
            contractDescription.ContractType = contractType; 
            if (contractAttr.HasProtectionLevel)
            { 
                contractDescription.ProtectionLevel = contractAttr.ProtectionLevel;
            }

            Type callbackType = contractAttr.CallbackContract; 

            EnsureCallbackType(callbackType); 
 
            EnsureSubcontract(contractAttr, contractType);
 
            // reflect the methods in contractType and add OperationDescriptions to ContractDescription
            reflectionInfo.iface = contractType;
            reflectionInfo.callbackiface = callbackType;
 
            contractDescription.SessionMode = contractAttr.SessionMode;
            contractDescription.CallbackContractType = callbackType; 
            contractDescription.ConfigurationName = contractAttr.ConfigurationName ?? contractType.FullName; 

            // get inherited operations 
            List types = ServiceReflector.GetInheritedContractTypes(contractType);
            List inheritedCallbackTypes = new List();
            for (int i = 0; i < types.Count; i++)
            { 
                Type inheritedContractType = types[i];
                ServiceContractAttribute inheritedContractAttr = ServiceReflector.GetRequiredSingleAttribute(inheritedContractType); 
                ContractDescription inheritedContractDescription = LoadContractDescriptionHelper(inheritedContractType, serviceType, serviceImplementation); 
                foreach (OperationDescription op in inheritedContractDescription.Operations)
                { 
                    if (!contractDescription.Operations.Contains(op)) // in a diamond hierarchy, ensure we don't add same op twice from two different parents
                    {
                        // ensure two different parents don't try to add conflicting operations
                        Collection existingOps = contractDescription.Operations.FindAll(op.Name); 
                        foreach (OperationDescription existingOp in existingOps)
                        { 
                            if (existingOp.Messages[0].Direction == op.Messages[0].Direction) 
                            {
                                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException( 
                                    SR.GetString(SR.CannotInheritTwoOperationsWithTheSameName3,
                                        op.Name, inheritedContractDescription.Name, existingOp.DeclaringContract.Name)));
                            }
                        } 
                        contractDescription.Operations.Add(op);
                    } 
                } 
                if (inheritedContractDescription.CallbackContractType != null)
                { 
                    inheritedCallbackTypes.Add(inheritedContractDescription.CallbackContractType);
                }
            }
 
            // this contract
            CreateOperationDescriptions(contractDescription, reflectionInfo, contractType, contractDescription, MessageDirection.Input); 
            // CallbackContract 
            if (callbackType != null && !inheritedCallbackTypes.Contains(callbackType))
            { 
                CreateOperationDescriptions(contractDescription, reflectionInfo, callbackType, contractDescription, MessageDirection.Output);
            }

            return contractDescription; 
        }
 
        internal static Attribute GetFormattingAttribute(ICustomAttributeProvider attrProvider, Attribute defaultFormatAttribute) 
        {
            if (attrProvider != null) 
            {
                if (attrProvider.IsDefined(typeof(XmlSerializerFormatAttribute), false))
                {
                    return ServiceReflector.GetSingleAttribute(attrProvider, formatterAttributes); 
                }
                if (attrProvider.IsDefined(typeof(DataContractFormatAttribute), false)) 
                { 
                    return ServiceReflector.GetSingleAttribute(attrProvider, formatterAttributes);
                } 
            }
            return defaultFormatAttribute;
        }
 
        //Sync and Async should follow the rules:
        //    1. Parameter match 
        //    2. Async cannot have behaviors (verification happens later in ProcessOpMethod - behaviors haven't yet been loaded here) 
        //    3. Async cannot have known types
        //    4. Async cannot have known faults 
        //    5. Sync and Async have to match on OneWay status
        //    6. Sync and Async have to match Action and ReplyAction
        void VerifyConsistency(OperationDescription syncOperation, OperationDescription asyncOperation)
        { 
            ParameterInfo[] syncInputs = ServiceReflector.GetInputParameters(syncOperation.SyncMethod, false);
            ParameterInfo[] asyncInputs = ServiceReflector.GetInputParameters(syncOperation.BeginMethod, true); 
            ParameterInfo[] syncOutputs = ServiceReflector.GetOutputParameters(syncOperation.SyncMethod, false); 
            ParameterInfo[] asyncOutputs = ServiceReflector.GetOutputParameters(syncOperation.EndMethod, true);
 
            if (syncInputs.Length != asyncInputs.Length || syncOutputs.Length != asyncOutputs.Length)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new InvalidOperationException(SR.GetString(SR.SyncAsyncMatchConsistency_Parameters5, 
                                                               syncOperation.SyncMethod.Name,
                                                               syncOperation.SyncMethod.DeclaringType, 
                                                               asyncOperation.BeginMethod.Name, 
                                                               asyncOperation.EndMethod.Name,
                                                               syncOperation.Name))); 
            }

            for (int i = 0; i < syncInputs.Length; i++)
            { 
                if (syncInputs[i].ParameterType != asyncInputs[i].ParameterType)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                        new InvalidOperationException(SR.GetString(SR.SyncAsyncMatchConsistency_Parameters5,
                                                                   syncOperation.SyncMethod.Name, 
                                                                   syncOperation.SyncMethod.DeclaringType,
                                                                   asyncOperation.BeginMethod.Name,
                                                                   asyncOperation.EndMethod.Name,
                                                                   syncOperation.Name))); 
                }
            } 
 
            for (int i = 0; i < syncOutputs.Length; i++)
            { 
                if (syncOutputs[i].ParameterType != asyncOutputs[i].ParameterType)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new InvalidOperationException(SR.GetString(SR.SyncAsyncMatchConsistency_Parameters5, 
                                                                   syncOperation.SyncMethod.Name,
                                                                   syncOperation.SyncMethod.DeclaringType, 
                                                                   asyncOperation.BeginMethod.Name, 
                                                                   asyncOperation.EndMethod.Name,
                                                                   syncOperation.Name))); 
                }
            }

            if (syncOperation.SyncMethod.ReturnType != syncOperation.EndMethod.ReturnType) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                    new InvalidOperationException(SR.GetString(SR.SyncAsyncMatchConsistency_ReturnType5, 
                                                               syncOperation.SyncMethod.Name,
                                                               syncOperation.SyncMethod.DeclaringType, 
                                                               asyncOperation.BeginMethod.Name,
                                                               asyncOperation.EndMethod.Name,
                                                               syncOperation.Name)));
            } 

            if (asyncOperation.Faults.Count != 0) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new InvalidOperationException(SR.GetString(SR.SyncAsyncMatchConsistency_Attributes6, 
                                                               syncOperation.SyncMethod.Name,
                                                               syncOperation.SyncMethod.DeclaringType,
                                                               asyncOperation.BeginMethod.Name,
                                                               asyncOperation.EndMethod.Name, 
                                                               syncOperation.Name,
                                                               typeof(FaultContractAttribute).Name))); 
            } 

            if (asyncOperation.KnownTypes.Count != 0) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new InvalidOperationException(SR.GetString(SR.SyncAsyncMatchConsistency_Attributes6,
                                                               syncOperation.SyncMethod.Name, 
                                                               syncOperation.SyncMethod.DeclaringType,
                                                               asyncOperation.BeginMethod.Name, 
                                                               asyncOperation.EndMethod.Name, 
                                                               syncOperation.Name,
                                                               typeof(ServiceKnownTypeAttribute).Name))); 
            }

            if (syncOperation.Messages.Count != asyncOperation.Messages.Count)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new InvalidOperationException(SR.GetString(SR.SyncAsyncMatchConsistency_Property6, 
                                                                   syncOperation.SyncMethod.Name, 
                                                                   syncOperation.SyncMethod.DeclaringType,
                                                                   asyncOperation.BeginMethod.Name, 
                                                                   asyncOperation.EndMethod.Name,
                                                                   syncOperation.Name,
                                                                   "IsOneWay")));
            } 

            for (int index = 0; index < syncOperation.Messages.Count; ++index) 
            { 
                if (syncOperation.Messages[index].Action != asyncOperation.Messages[index].Action)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new InvalidOperationException(SR.GetString(SR.SyncAsyncMatchConsistency_Property6,
                                                                   syncOperation.SyncMethod.Name,
                                                                   syncOperation.SyncMethod.DeclaringType, 
                                                                   asyncOperation.BeginMethod.Name,
                                                                   asyncOperation.EndMethod.Name, 
                                                                   syncOperation.Name, 
                                                                   index == 0 ? "Action" : "ReplyAction")));
                } 
            }
        }

        // "direction" is the "direction of the interface" (from the perspective of the server, as usual): 
        //    proxy interface on client: MessageDirection.Input
        //    callback interface on client: MessageDirection.Output 
        //    service interface (or class) on server: MessageDirection.Input 
        //    callback interface on server: MessageDirection.Output
        OperationDescription CreateOperationDescription(ContractDescription contractDescription, MethodInfo methodInfo, MessageDirection direction, 
                                                        ContractReflectionInfo reflectionInfo, ContractDescription declaringContract)
        {
            OperationContractAttribute opAttr = ServiceReflector.GetSingleAttribute(methodInfo);
            if (opAttr == null) 
            {
                return null; 
            } 
            if (ServiceReflector.HasEndMethodShape(methodInfo))
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                    SR.GetString(SR.EndMethodsCannotBeDecoratedWithOperationContractAttribute,
                                 methodInfo.Name, reflectionInfo.iface)));
            } 

            bool isAsync = ServiceReflector.IsBegin(opAttr, methodInfo); 
            XmlName operationName = NamingHelper.GetOperationName(ServiceReflector.GetLogicalName(methodInfo, isAsync), opAttr.Name); 

            Collection operations = contractDescription.Operations.FindAll(operationName.EncodedName); 
            for (int i = 0; i < operations.Count; i++)
            {
                OperationDescription existingOp = operations[i];
                if (existingOp.Messages[0].Direction == direction) 
                {
                    if (isAsync && (existingOp.BeginMethod != null)) 
                    { 
                        string method1Name = existingOp.BeginMethod.Name;
                        string method2Name = methodInfo.Name; 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CannotHaveTwoOperationsWithTheSameName3, method1Name, method2Name, reflectionInfo.iface)));
                    }
                    if (!isAsync && (existingOp.SyncMethod != null))
                    { 
                        string method1Name = existingOp.SyncMethod.Name;
                        string method2Name = methodInfo.Name; 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CannotHaveTwoOperationsWithTheSameName3, method1Name, method2Name, reflectionInfo.iface))); 
                    }
 
                    contractDescription.Operations.Remove(existingOp);
                    OperationDescription newOp = CreateOperationDescription(contractDescription,
                                                                            methodInfo,
                                                                            direction, 
                                                                            reflectionInfo,
                                                                            declaringContract); 
 
                    newOp.HasNoDisposableParameters = ServiceReflector.HasNoDisposableParameters(methodInfo);
 
                    if (isAsync)
                    {
                        existingOp.BeginMethod = newOp.BeginMethod;
                        existingOp.EndMethod = newOp.EndMethod; 
                        VerifyConsistency(existingOp, newOp);
                        return existingOp; 
                    } 
                    else
                    { 
                        newOp.BeginMethod = existingOp.BeginMethod;
                        newOp.EndMethod = existingOp.EndMethod;
                        VerifyConsistency(newOp, existingOp);
                        return newOp; 
                    }
                } 
            } 

            OperationDescription operationDescription = new OperationDescription(operationName.EncodedName, declaringContract); 
            operationDescription.IsInitiating = opAttr.IsInitiating;
            operationDescription.IsTerminating = opAttr.IsTerminating;
            operationDescription.HasNoDisposableParameters = ServiceReflector.HasNoDisposableParameters(methodInfo);
 
            if (opAttr.HasProtectionLevel)
            { 
                operationDescription.ProtectionLevel = opAttr.ProtectionLevel; 
            }
 
            XmlQualifiedName contractQname = new XmlQualifiedName(declaringContract.Name, declaringContract.Namespace);

            object[] methodAttributes = ServiceReflector.GetCustomAttributes(methodInfo, typeof(FaultContractAttribute), false);
 
            if (opAttr.IsOneWay && methodAttributes.Length > 0)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.OneWayAndFaultsIncompatible2, methodInfo.DeclaringType.FullName, operationName.EncodedName))); 
            }
 
            for (int i = 0; i < methodAttributes.Length; i++)
            {
                FaultContractAttribute knownFault = (FaultContractAttribute)methodAttributes[i];
                FaultDescription faultDescription = CreateFaultDescription(knownFault, contractQname, declaringContract.Namespace, operationDescription.XmlName); 
                CheckDuplicateFaultContract(operationDescription.Faults, faultDescription, operationName.EncodedName);
                operationDescription.Faults.Add(faultDescription); 
            } 

            methodAttributes = ServiceReflector.GetCustomAttributes(methodInfo, typeof(ServiceKnownTypeAttribute), false); 
            IEnumerable knownTypes = GetKnownTypes(methodAttributes, methodInfo);
            foreach(Type knownType in knownTypes)
                operationDescription.KnownTypes.Add(knownType);
 
            MessageDirection requestDirection = direction;
            MessageDirection responseDirection = MessageDirectionHelper.Opposite(direction); 
 
            string requestAction = NamingHelper.GetMessageAction(contractQname,
                                                                   operationDescription.CodeName, 
                                                                   opAttr.Action,
                                                                   false);

            string responseAction = NamingHelper.GetMessageAction(contractQname, 
                                                                  operationDescription.CodeName,
                                                                  opAttr.ReplyAction, 
                                                                  true); 
            XmlName wrapperName = operationName;
            XmlName wrapperResponseName = GetBodyWrapperResponseName(operationName); 
            string wrapperNamespace = declaringContract.Namespace;

            MessageDescription requestDescription = CreateMessageDescription(methodInfo,
                                                           isAsync, 
                                                           null,
                                                           contractDescription.Namespace, 
                                                           requestAction, 
                                                           wrapperName,
                                                           wrapperNamespace, 
                                                           requestDirection);
            MessageDescription responseDescription = null;
            operationDescription.Messages.Add(requestDescription);
            MethodInfo outputMethod = methodInfo; 
            if (!isAsync)
            { 
                operationDescription.SyncMethod = methodInfo; 
            }
            else 
            {
                outputMethod = ServiceReflector.GetEndMethod(methodInfo);
                operationDescription.EndMethod = outputMethod;
                operationDescription.BeginMethod = methodInfo; 
            }
 
            if (!opAttr.IsOneWay) 
            {
                XmlName returnValueName = GetReturnValueName(operationName); 
                responseDescription = CreateMessageDescription(outputMethod,
                                                                isAsync,
                                                                returnValueName,
                                                                contractDescription.Namespace, 
                                                                responseAction,
                                                                wrapperResponseName, 
                                                                wrapperNamespace, 
                                                                responseDirection);
                operationDescription.Messages.Add(responseDescription); 
            }
            else
            {
                if (outputMethod.ReturnType != typeof(void) || 
                    ServiceReflector.HasOutputParameters(outputMethod, isAsync))
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ServiceOperationsMarkedWithIsOneWayTrueMust0))); 
                }
 
                if (opAttr.ReplyAction != null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.OneWayOperationShouldNotSpecifyAReplyAction1, operationName)));
                } 
            }
 
            if (!opAttr.IsOneWay) 
            {
                if (responseDescription.IsVoid && 
                    (requestDescription.IsUntypedMessage || requestDescription.IsTypedMessage))
                {
                    responseDescription.Body.WrapperName = responseDescription.Body.WrapperNamespace = null;
                } 
                else if (requestDescription.IsVoid &&
                    (responseDescription.IsUntypedMessage || responseDescription.IsTypedMessage)) 
                { 
                    requestDescription.Body.WrapperName = requestDescription.Body.WrapperNamespace = null;
                } 
            }


            return operationDescription; 
        }
 
        private void CheckDuplicateFaultContract(FaultDescriptionCollection faultDescriptionCollection, FaultDescription fault, string operationName) 
        {
            foreach (FaultDescription existingFault in faultDescriptionCollection) 
            {
                if (XmlName.IsNullOrEmpty(existingFault.ElementName) && XmlName.IsNullOrEmpty(fault.ElementName) && existingFault.DetailType == fault.DetailType)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
                        SR.GetString(SR.SFxFaultContractDuplicateDetailType, operationName, fault.DetailType))); 
                if (!XmlName.IsNullOrEmpty(existingFault.ElementName) && !XmlName.IsNullOrEmpty(fault.ElementName) && existingFault.ElementName == fault.ElementName && existingFault.Namespace == fault.Namespace)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException( 
                        SR.GetString(SR.SFxFaultContractDuplicateElement, operationName, fault.ElementName, fault.Namespace))); 
            }
        } 

        FaultDescription CreateFaultDescription(FaultContractAttribute attr,
                                                XmlQualifiedName contractName,
                                                string contractNamespace, 
                                                XmlName operationName)
        { 
            XmlName faultName = new XmlName(attr.Name ?? NamingHelper.TypeName(attr.DetailType) + FaultSuffix); 
            FaultDescription fault = new FaultDescription(NamingHelper.GetMessageAction(contractName, operationName.DecodedName + faultName.DecodedName, attr.Action, false/*isResponse*/));
            if (attr.Name != null) 
                fault.SetNameAndElement(faultName);
            else
                fault.SetNameOnly(faultName);
            fault.Namespace = attr.Namespace ?? contractNamespace; 
            fault.DetailType = attr.DetailType;
            if (attr.HasProtectionLevel) 
            { 
                fault.ProtectionLevel = attr.ProtectionLevel;
            } 
            return fault;
        }

        MessageDescription CreateMessageDescription(MethodInfo methodInfo, 
                                                           bool isAsync,
                                                           XmlName returnValueName, 
                                                           string defaultNS, 
                                                           string action,
                                                           XmlName wrapperName, 
                                                           string wrapperNamespace,
                                                           MessageDirection direction)
        {
            string methodName = methodInfo.Name; 
            MessageDescription messageDescription;
            if (returnValueName == null) 
            { 
                ParameterInfo[] parameters = ServiceReflector.GetInputParameters(methodInfo, isAsync);
                if (parameters.Length == 1 && parameters[0].ParameterType.IsDefined(typeof(MessageContractAttribute), false)) 
                {
                    messageDescription =  CreateTypedMessageDescription(parameters[0].ParameterType,
                                                                null,
                                                                null, 
                                                                defaultNS,
                                                                action, 
                                                                direction); 
                }
                else 
                {
                    messageDescription = CreateParameterMessageDescription(parameters,
                                                             null,
                                                             null, 
                                                             null,
                                                             methodName, 
                                                             defaultNS, 
                                                             action,
                                                             wrapperName, 
                                                             wrapperNamespace,
                                                             direction);
                }
            } 
            else
            { 
                ParameterInfo[] parameters = ServiceReflector.GetOutputParameters(methodInfo, isAsync); 
                Type responseType = methodInfo.ReturnType;
                if (responseType.IsDefined(typeof(MessageContractAttribute), false) && parameters.Length == 0) 
                {
                    messageDescription = CreateTypedMessageDescription(responseType,
                                                         methodInfo.ReturnTypeCustomAttributes,
                                                         returnValueName, 
                                                         defaultNS,
                                                         action, 
                                                         direction); 
                }
                else 
                {
                    messageDescription = CreateParameterMessageDescription(parameters,
                                                         methodInfo.ReturnType,
                                                         methodInfo.ReturnTypeCustomAttributes, 
                                                         returnValueName,
                                                         methodName, 
                                                         defaultNS, 
                                                         action,
                                                         wrapperName, 
                                                         wrapperNamespace,
                                                         direction);
                }
            } 

            bool hasUnknownHeaders = false; 
            for (int i = 0; i < messageDescription.Headers.Count; i++) 
            {
                MessageHeaderDescription header = messageDescription.Headers[i]; 
                if(header.IsUnknownHeaderCollection)
                {
                    if(hasUnknownHeaders)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxMultipleUnknownHeaders, methodInfo, methodInfo.DeclaringType)));
                    } 
                    else 
                    {
                        hasUnknownHeaders = true; 
                    }
                }
            }
            return messageDescription; 
        }
 
        MessageDescription CreateParameterMessageDescription(ParameterInfo[] parameters, 
                                                  Type returnType,
                                                  ICustomAttributeProvider returnAttrProvider, 
                                                  XmlName returnValueName,
                                                  string methodName,
                                                  string defaultNS,
                                                  string action, 
                                                  XmlName wrapperName,
                                                  string wrapperNamespace, 
                                                  MessageDirection direction) 
        {
            foreach (ParameterInfo param in parameters) 
            {
                if (GetParameterType(param).IsDefined(typeof(MessageContractAttribute), false/*inherit*/))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidMessageContractSignature, methodName))); 
                }
            } 
            if (returnType != null && returnType.IsDefined(typeof(MessageContractAttribute), false/*inherit*/)) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidMessageContractSignature, methodName))); 
            }

            MessageDescription messageDescription = new MessageDescription(action, direction);
            MessagePartDescriptionCollection partDescriptionCollection = messageDescription.Body.Parts; 
            for (int index = 0; index < parameters.Length; index++)
            { 
                MessagePartDescription partDescription = CreateParameterPartDescription(new XmlName(parameters[index].Name), defaultNS, index, parameters[index], GetParameterType(parameters[index])); 
                if (partDescriptionCollection.Contains(new XmlQualifiedName(partDescription.Name, partDescription.Namespace)))
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidMessageContractException(SR.GetString(SR.SFxDuplicateMessageParts, partDescription.Name, partDescription.Namespace))); 
                messageDescription.Body.Parts.Add(partDescription);
            }

            if (returnType != null) 
            {
                messageDescription.Body.ReturnValue = CreateParameterPartDescription(returnValueName, defaultNS, 0, returnAttrProvider, returnType); 
            } 
            if (messageDescription.IsUntypedMessage)
            { 
                messageDescription.Body.WrapperName = null;
                messageDescription.Body.WrapperNamespace = null;
            }
            else 
            {
                messageDescription.Body.WrapperName = wrapperName.EncodedName; 
                messageDescription.Body.WrapperNamespace = wrapperNamespace; 
            }
 
            return messageDescription;
        }

        private static MessagePartDescription CreateParameterPartDescription(XmlName defaultName, string defaultNS, int index, ICustomAttributeProvider attrProvider, Type type) 
        {
            MessagePartDescription parameterPart; 
            MessageParameterAttribute paramAttr = ServiceReflector.GetSingleAttribute(attrProvider); 

            XmlName name = paramAttr == null || !paramAttr.IsNameSetExplicit ? defaultName : new XmlName(paramAttr.Name); 
            parameterPart = new MessagePartDescription(name.EncodedName, defaultNS);
            parameterPart.Type = type;
            parameterPart.Index = index;
            parameterPart.AdditionalAttributesProvider = attrProvider; 
            return parameterPart;
        } 
 

        internal MessageDescription CreateTypedMessageDescription(Type typedMessageType, 
                                                  ICustomAttributeProvider returnAttrProvider,
                                                  XmlName returnValueName,
                                                  string defaultNS,
                                                  string action, 
                                                  MessageDirection direction)
        { 
 

            MessageDescription messageDescription; 
            bool messageItemsInitialized = false;
            MessageDescriptionItems messageItems;
            MessageContractAttribute messageContractAttribute = ServiceReflector.GetSingleAttribute(typedMessageType);
            if (messages.TryGetValue(typedMessageType, out messageItems)) 
            {
                messageDescription = new MessageDescription(action, direction, messageItems); 
                messageItemsInitialized = true; 
            }
            else 
                messageDescription = new MessageDescription(action, direction, null);
            messageDescription.MessageType = typedMessageType;
            messageDescription.MessageName = new XmlName(NamingHelper.TypeName(typedMessageType));
            if (messageContractAttribute.IsWrapped) 
            {
                messageDescription.Body.WrapperName = GetWrapperName(messageContractAttribute.WrapperName, messageDescription.MessageName).EncodedName; 
                messageDescription.Body.WrapperNamespace = messageContractAttribute.WrapperNamespace ?? defaultNS; 
            }
            List contractMembers = new List(); 

            for (Type baseType = typedMessageType; baseType != null && baseType != typeof(object) && baseType != typeof(ValueType); baseType = baseType.BaseType)
            {
                if (!baseType.IsDefined(typeof(MessageContractAttribute), false/*inherit*/)) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxMessageContractBaseTypeNotValid, baseType, typedMessageType))); 
                } 
                if (!messageDescription.HasProtectionLevel)
                { 
                    MessageContractAttribute mca = ServiceReflector.GetRequiredSingleAttribute(baseType);
                    if (mca.HasProtectionLevel)
                    {
                        messageDescription.ProtectionLevel = mca.ProtectionLevel; 
                    }
                } 
 
                if (messageItemsInitialized)
                    continue; 
                foreach (MemberInfo memberInfo in baseType.GetMembers(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
                {
                    if (memberInfo.MemberType != MemberTypes.Field &&
                        memberInfo.MemberType != MemberTypes.Property) 
                    {
                        continue; 
                    } 
                    PropertyInfo property = memberInfo as PropertyInfo;
                    if (property != null) 
                    {
                        MethodInfo getMethod = property.GetGetMethod(true);
                        if (getMethod != null && IsMethodOverriding(getMethod))
                        { 
                            continue;
                        } 
                        MethodInfo setMethod = property.GetSetMethod(true); 
                        if (setMethod != null && IsMethodOverriding(setMethod))
                        { 
                            continue;
                        }
                    }
 
                    if (memberInfo.IsDefined(typeof(MessageBodyMemberAttribute), false) ||
                        memberInfo.IsDefined(typeof(MessageHeaderAttribute), false) || 
                        memberInfo.IsDefined(typeof(MessageHeaderArrayAttribute), false) || 
                        memberInfo.IsDefined(typeof(MessagePropertyAttribute), false)
                        ) 
                    {
                        contractMembers.Add(memberInfo);
                    }
                } 
            }
 
            if (messageItemsInitialized) 
                return messageDescription;
 
            List bodyPartDescriptionList = new List();
            List headerPartDescriptionList = new List();
            for (int i = 0; i < contractMembers.Count; i++)
            { 
                MemberInfo memberInfo = contractMembers[i];
 
                Type memberType; 
                if (memberInfo.MemberType == MemberTypes.Property)
                { 
                    memberType = ((PropertyInfo)memberInfo).PropertyType;
                }
                else
                { 
                    memberType = ((FieldInfo)memberInfo).FieldType;
                } 
 
                if (memberInfo.IsDefined(typeof(MessageHeaderArrayAttribute), false)
                    || memberInfo.IsDefined(typeof(MessageHeaderAttribute), false)) 
                {
                    headerPartDescriptionList.Add(CreateMessageHeaderDescription(memberType,
                                                                              memberInfo,
                                                                              new XmlName(memberInfo.Name), 
                                                                              defaultNS,
                                                                              i, 
                                                                              -1)); 
                }
                else if (memberInfo.IsDefined(typeof(MessagePropertyAttribute), false)) 
                {
                    messageDescription.Properties.Add(CreateMessagePropertyDescription(memberInfo,
                                                                              new XmlName(memberInfo.Name),
                                                                              i)); 
                }
                else 
                { 
                    bodyPartDescriptionList.Add(CreateMessagePartDescription(memberType,
                                                                         memberInfo, 
                                                                         new XmlName(memberInfo.Name),
                                                                         defaultNS,
                                                                         i,
                                                                         -1)); 
                }
            } 
 
            if (returnAttrProvider != null)
            { 
                messageDescription.Body.ReturnValue = CreateMessagePartDescription(typeof(void),
                                                                  returnAttrProvider,
                                                                  returnValueName,
                                                                  defaultNS, 
                                                                  0,
                                                                  0); 
            } 

            AddSortedParts(bodyPartDescriptionList, messageDescription.Body.Parts); 
            AddSortedParts(headerPartDescriptionList, messageDescription.Headers);
            messages.Add(typedMessageType, messageDescription.Items);

            return messageDescription; 
        }
 
        static bool IsMethodOverriding(MethodInfo method) 
        {
            return method.IsVirtual && ((method.Attributes & MethodAttributes.NewSlot) == 0); 
        }


 

        MessagePartDescription CreateMessagePartDescription(Type bodyType, 
                                                         ICustomAttributeProvider attrProvider, 
                                                         XmlName defaultName,
                                                         string defaultNS, 
                                                         int parameterIndex,
                                                         int serializationIndex)
        {
            MessagePartDescription partDescription = null; 
            MessageBodyMemberAttribute bodyAttr = ServiceReflector.GetSingleAttribute(attrProvider, messageContractMemberAttributes);
 
            if (bodyAttr == null) 
            {
                partDescription = new MessagePartDescription(defaultName.EncodedName, defaultNS); 
                partDescription.SerializationPosition = serializationIndex;
            }
            else
            { 
                XmlName partName = bodyAttr.IsNameSetExplicit ? new XmlName(bodyAttr.Name) : defaultName;
                string partNs = bodyAttr.IsNamespaceSetExplicit ? bodyAttr.Namespace : defaultNS; 
                partDescription = new MessagePartDescription(partName.EncodedName, partNs); 
                partDescription.SerializationPosition = bodyAttr.Order < 0 ? serializationIndex : bodyAttr.Order;
                if (bodyAttr.HasProtectionLevel) 
                {
                    partDescription.ProtectionLevel = bodyAttr.ProtectionLevel;
                }
            } 

            if (attrProvider is MemberInfo) 
            { 
                partDescription.MemberInfo = (MemberInfo)attrProvider;
            } 
            partDescription.Type = bodyType;
            partDescription.Index = parameterIndex;
            return partDescription;
        } 

        MessageHeaderDescription CreateMessageHeaderDescription(Type headerParameterType, 
                                                                    ICustomAttributeProvider attrProvider, 
                                                                    XmlName defaultName,
                                                                    string defaultNS, 
                                                                    int parameterIndex,
                                                                    int serializationPosition)
        {
            MessageHeaderDescription headerDescription = null; 
            MessageHeaderAttribute headerAttr = ServiceReflector.GetRequiredSingleAttribute(attrProvider, messageContractMemberAttributes);
            XmlName headerName = headerAttr.IsNameSetExplicit ? new XmlName(headerAttr.Name) : defaultName; 
            string headerNs = headerAttr.IsNamespaceSetExplicit ? headerAttr.Namespace : defaultNS; 
            headerDescription = new MessageHeaderDescription(headerName.EncodedName, headerNs);
            headerDescription.UniquePartName = defaultName.EncodedName; 

            if (headerAttr is MessageHeaderArrayAttribute)
            {
                if (!headerParameterType.IsArray || headerParameterType.GetArrayRank() != 1) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidMessageHeaderArrayType, defaultName))); 
                } 
                headerDescription.Multiple = true;
                headerParameterType = headerParameterType.GetElementType(); 
            }
            headerDescription.Type = TypedHeaderManager.GetHeaderType(headerParameterType);
            headerDescription.TypedHeader = (headerParameterType != headerDescription.Type);
            if(headerDescription.TypedHeader) 
            {
                if(headerAttr.IsMustUnderstandSet || headerAttr.IsRelaySet || headerAttr.Actor != null) 
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxStaticMessageHeaderPropertiesNotAllowed, defaultName)));
                } 
            }
            else
            {
                headerDescription.Actor = headerAttr.Actor; 
                headerDescription.MustUnderstand = headerAttr.MustUnderstand;
                headerDescription.Relay = headerAttr.Relay; 
            } 
            headerDescription.SerializationPosition = serializationPosition;
            if (headerAttr.HasProtectionLevel) 
            {
                headerDescription.ProtectionLevel = headerAttr.ProtectionLevel;
            }
            if (attrProvider is MemberInfo) 
            {
                headerDescription.MemberInfo = (MemberInfo)attrProvider; 
            } 

            headerDescription.Index = parameterIndex; 
            return headerDescription;
        }

        MessagePropertyDescription CreateMessagePropertyDescription(ICustomAttributeProvider attrProvider, 
                                                            XmlName defaultName,
                                                            int parameterIndex) 
        { 
            MessagePropertyAttribute attr = ServiceReflector.GetSingleAttribute(attrProvider, messageContractMemberAttributes);
            XmlName propertyName = attr.IsNameSetExplicit ? new XmlName(attr.Name) : defaultName; 
            MessagePropertyDescription propertyDescription = new MessagePropertyDescription(propertyName.EncodedName);
            propertyDescription.Index = parameterIndex;

            if (attrProvider is MemberInfo) 
            {
                propertyDescription.MemberInfo = (MemberInfo)attrProvider; 
            } 

            return propertyDescription; 
        }

        internal static XmlName GetReturnValueName(XmlName methodName)
        { 
            return new XmlName(methodName.EncodedName + ReturnSuffix, true);
        } 
 
        internal static XmlName GetReturnValueName(string methodName)
        { 
            return new XmlName(methodName + ReturnSuffix);
        }

        internal static Type GetParameterType(ParameterInfo parameterInfo) 
        {
            Type parameterType = parameterInfo.ParameterType; 
            if (parameterType.IsByRef) 
            {
                return parameterType.GetElementType(); 
            }
            else
            {
                return parameterType; 
            }
        } 
 
        internal static XmlName GetWrapperName(string wrapperName, XmlName defaultName)
        { 
            if (string.IsNullOrEmpty(wrapperName))
                return defaultName;
            return new XmlName(wrapperName);
        } 

        void AddSortedParts(List partDescriptionList, KeyedCollection partDescriptionCollection) 
            where T : MessagePartDescription 
        {
            MessagePartDescription[] partDescriptions = partDescriptionList.ToArray(); 
            if (partDescriptions.Length > 1)
            {
                Array.Sort(partDescriptions, CompareMessagePartDescriptions);
            } 
            foreach (T partDescription in partDescriptions)
            { 
                if(partDescriptionCollection.Contains(new XmlQualifiedName(partDescription.Name, partDescription.Namespace))) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidMessageContractException(SR.GetString(SR.SFxDuplicateMessageParts, partDescription.Name, partDescription.Namespace))); 
                }
                partDescriptionCollection.Add(partDescription);
            }
        } 

        class ContractReflectionInfo 
        { 
            internal Type iface;
            internal Type callbackiface; 
        }

        // This function factors out the logic of how programming model attributes interact with service inheritance.
        // See MB 37427 for details. 
        //
        // To use this, just call ApplyServiceInheritance() with 
        //  - the service type you want to pull behavior attributes from 
        //  - the "destination" behavior collection, where all the right behavior attributes should be added to
        //  - a delegate 
        // The delegate is just a function you write that behaves like this:
        //    imagine that "currentType" was the only type (imagine there was no inheritance hierarchy)
        //    find desired behavior attributes on this type, and add them to "behaviors"
        // ApplyServiceInheritance then uses the logic you provide for getting behavior attributes from a single type, 
        // and it walks the actual type hierarchy and does the inheritance/override logic for you.
        public static void ApplyServiceInheritance( 
                     Type serviceType, 
                     TBehaviorCollection descriptionBehaviors,
                     ServiceInheritanceCallback callback) 
            where IBehavior : class
            where TBehaviorCollection : KeyedByTypeCollection
        {
            // work our way up the class hierarchy, looking for attributes; adding "bottom up" so that for each 
            // type of attribute, we only pick up the bottom-most one (the one attached to most-derived class)
            for (Type currentType = serviceType; currentType != null; currentType = currentType.BaseType) 
            { 
                AddBehaviorsAtOneScope(currentType, descriptionBehaviors, callback);
            } 
        }

        public delegate void ServiceInheritanceCallback(Type currentType, KeyedByTypeCollection behaviors);
 
        // To use this, just call AddBehaviorsAtOneScope() with
        //  - the type you want to pull behavior attributes from 
        //  - the "destination" behavior collection, where all the right behavior attributes should be added to 
        //  - a delegate
        // The delegate is just a function you write that behaves like this: 
        //    imagine that "currentType" was the only type (imagine there was no inheritance hierarchy)
        //    find desired behavior attributes on this type, and add them to "behaviors"
        // AddBehaviorsAtOneScope then uses the logic you provide for getting behavior attributes from a single type,
        // and it does the override logic for you (only add the behavior if it wasn't already in the descriptionBehaviors) 
        static void AddBehaviorsAtOneScope(
                     Type type, 
                     TBehaviorCollection descriptionBehaviors, 
                     ServiceInheritanceCallback callback)
            where IBehavior : class 
            where TBehaviorCollection : KeyedByTypeCollection
        {
            KeyedByTypeCollection toAdd = new KeyedByTypeCollection();
            callback(type, toAdd); 
            // toAdd now contains the set of behaviors we'd add if this type (scope) were the only source of behaviors
 
            for (int i = 0; i < toAdd.Count; i++) 
            {
                IBehavior behavior = toAdd[i]; 
                if (!descriptionBehaviors.Contains(behavior.GetType()))
                {
                    // if we didn't already see this type of attribute at a previous scope
                    // then it belongs in the final result 
                    if (behavior is ServiceBehaviorAttribute || behavior is CallbackBehaviorAttribute)
                    { 
                        descriptionBehaviors.Insert(0, behavior); 
                    }
                    else 
                    {
                        descriptionBehaviors.Add(behavior);
                    }
                } 
            }
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK