File: System\ServiceModel\Description\MetadataResolver.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
namespace System.ServiceModel.Description
{
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Diagnostics;
    using System.Runtime;
    using System.Runtime.Diagnostics;
    using System.ServiceModel;
    using System.ServiceModel.Diagnostics;
    using System.Xml;
 
    public static class MetadataResolver
    {
        public static ServiceEndpointCollection Resolve(Type contract, EndpointAddress address)
        {
            if (contract == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contract");
            }
 
            return Resolve(CreateContractCollection(contract), address);
        }
        public static ServiceEndpointCollection Resolve(IEnumerable<ContractDescription> contracts, EndpointAddress address)
        {
            return Resolve(contracts, address, new MetadataExchangeClient(address));
        }
        public static ServiceEndpointCollection Resolve(IEnumerable<ContractDescription> contracts, EndpointAddress address, MetadataExchangeClient client)
        {
            if (address == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("address");
            }
            if (client == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("client");
            }
            if (contracts == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contracts");
            }
            ValidateContracts(contracts);
 
 
            MetadataSet metadataSet = client.GetMetadata(address);
            return ImportEndpoints(metadataSet, contracts, client);
        }
 
        public static ServiceEndpointCollection Resolve(Type contract, Uri address, MetadataExchangeClientMode mode)
        {
            if (contract == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contract");
            }
 
            return Resolve(CreateContractCollection(contract), address, mode);
        }
        public static ServiceEndpointCollection Resolve(IEnumerable<ContractDescription> contracts, Uri address, MetadataExchangeClientMode mode)
        {
            return Resolve(contracts, address, mode, new MetadataExchangeClient(address, mode));
        }
        public static ServiceEndpointCollection Resolve(IEnumerable<ContractDescription> contracts, Uri address, MetadataExchangeClientMode mode, MetadataExchangeClient client)
        {
            if (address == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("address");
            }
            MetadataExchangeClientModeHelper.Validate(mode);
            if (client == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("client");
            }
            if (contracts == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contracts");
            }
            ValidateContracts(contracts);
 
            MetadataSet metadataSet = client.GetMetadata(address, mode);
            return ImportEndpoints(metadataSet, contracts, client);
        }
 
        public static IAsyncResult BeginResolve(Type contract, EndpointAddress address, AsyncCallback callback, object asyncState)
        {
            if (contract == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contract");
            }
 
            return BeginResolve(CreateContractCollection(contract), address, callback, asyncState);
        }
        public static IAsyncResult BeginResolve(IEnumerable<ContractDescription> contracts, EndpointAddress address, AsyncCallback callback, object asyncState)
        {
            return BeginResolve(contracts, address, new MetadataExchangeClient(address), callback, asyncState);
        }
        public static IAsyncResult BeginResolve(IEnumerable<ContractDescription> contracts, EndpointAddress address, MetadataExchangeClient client, AsyncCallback callback, object asyncState)
        {
            if (address == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("address");
            }
            if (client == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("client");
            }
            if (contracts == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contracts");
            }
            ValidateContracts(contracts);
 
            return new AsyncMetadataResolverHelper(address, MetadataExchangeClientMode.MetadataExchange, client, contracts, callback, asyncState);
        }
 
        public static IAsyncResult BeginResolve(Type contract, Uri address, MetadataExchangeClientMode mode, AsyncCallback callback, object asyncState)
        {
            if (contract == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contract");
            }
 
            return BeginResolve(CreateContractCollection(contract), address, mode, callback, asyncState);
        }
        public static IAsyncResult BeginResolve(IEnumerable<ContractDescription> contracts, Uri address, MetadataExchangeClientMode mode, AsyncCallback callback, object asyncState)
        {
            return BeginResolve(contracts, address, mode, new MetadataExchangeClient(address, mode), callback, asyncState);
        }
        public static IAsyncResult BeginResolve(IEnumerable<ContractDescription> contracts, Uri address, MetadataExchangeClientMode mode, MetadataExchangeClient client,
                                                 AsyncCallback callback, object asyncState)
        {
            if (address == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("address");
            }
            MetadataExchangeClientModeHelper.Validate(mode);
            if (client == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("client");
            }
            if (contracts == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("contracts");
            }
            ValidateContracts(contracts);
 
            return new AsyncMetadataResolverHelper(new EndpointAddress(address), mode, client, contracts, callback, asyncState);
        }
 
        public static ServiceEndpointCollection EndResolve(IAsyncResult result)
        {
            return AsyncMetadataResolverHelper.EndAsyncCall(result);
        }
 
        class AsyncMetadataResolverHelper : AsyncResult
        {
            MetadataExchangeClient client;
            EndpointAddress address;
            ServiceEndpointCollection endpointCollection;
            MetadataExchangeClientMode mode;
            IEnumerable<ContractDescription> knownContracts;
 
            internal AsyncMetadataResolverHelper(EndpointAddress address, MetadataExchangeClientMode mode, MetadataExchangeClient client, IEnumerable<ContractDescription> knownContracts, AsyncCallback callback, object asyncState)
                : base(callback, asyncState)
            {
                this.address = address;
                this.client = client;
                this.mode = mode;
                this.knownContracts = knownContracts;
 
                GetMetadataSetAsync();
            }
 
            internal void GetMetadataSetAsync()
            {
                IAsyncResult result;
 
                if (this.mode == MetadataExchangeClientMode.HttpGet)
                {
                    result = this.client.BeginGetMetadata(this.address.Uri, MetadataExchangeClientMode.HttpGet, Fx.ThunkCallback(new AsyncCallback(this.EndGetMetadataSet)), null);
                }
                else
                {
                    result = this.client.BeginGetMetadata(this.address, Fx.ThunkCallback(new AsyncCallback(this.EndGetMetadataSet)), null);
                }
 
                if (result.CompletedSynchronously)
                {
                    HandleResult(result);
                    this.Complete(true);
                }
            }
 
            internal void EndGetMetadataSet(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                    return;
 
                Exception exception = null;
                try
                {
                    HandleResult(result);
 
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                        throw;
                    exception = e;
                }
                this.Complete(false, exception);
 
            }
 
            private void HandleResult(IAsyncResult result)
            {
                MetadataSet metadataSet = this.client.EndGetMetadata(result);
                endpointCollection = ImportEndpoints(metadataSet, knownContracts, this.client);
            }
 
            internal static ServiceEndpointCollection EndAsyncCall(IAsyncResult result)
            {
                AsyncMetadataResolverHelper helper = AsyncResult.End<AsyncMetadataResolverHelper>(result);
                return helper.endpointCollection;
            }
        }
 
        private static ServiceEndpointCollection ImportEndpoints(MetadataSet metadataSet, IEnumerable<ContractDescription> contracts, MetadataExchangeClient client)
        {
            ServiceEndpointCollection endpoints = new ServiceEndpointCollection();
 
            WsdlImporter importer = new WsdlImporter(metadataSet);
 
            // remember the original proxy so user doesn't need to set it again 
            importer.State.Add(MetadataExchangeClient.MetadataExchangeClientKey, client);
 
            foreach (ContractDescription cd in contracts)
            {
                importer.KnownContracts.Add(WsdlExporter.WsdlNamingHelper.GetPortTypeQName(cd), cd);
            }
 
            foreach (ContractDescription cd in contracts)
            {
                ServiceEndpointCollection contractEndpoints;
                contractEndpoints = importer.ImportEndpoints(cd);
                foreach (ServiceEndpoint se in contractEndpoints)
                {
                    endpoints.Add(se);
                }
            }
 
            //Trace all warnings and errors
            if (importer.Errors.Count > 0)
            {
                TraceWsdlImportErrors(importer);
            }
 
            return endpoints;
        }
 
        static void TraceWsdlImportErrors(WsdlImporter importer)
        {
            foreach (MetadataConversionError error in importer.Errors)
            {
                if (DiagnosticUtility.ShouldTraceWarning)
                {
                    Hashtable h = new Hashtable(2)
                    {
                        { "IsWarning", error.IsWarning },
                        { "Message", error.Message }
                    };
                    TraceUtility.TraceEvent(TraceEventType.Warning, TraceCode.WsmexNonCriticalWsdlExportError,
                        SR.GetString(SR.TraceCodeWsmexNonCriticalWsdlExportError), new DictionaryTraceRecord(h), null, null);
                }
            }
        }
 
        private static void ValidateContracts(IEnumerable<ContractDescription> contracts)
        {
            bool isEmpty = true;
            Collection<XmlQualifiedName> qnames = new Collection<XmlQualifiedName>();
            foreach (ContractDescription cd in contracts)
            {
                isEmpty = false;
                if (cd == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxMetadataResolverKnownContractsCannotContainNull));
                }
 
                XmlQualifiedName qname = WsdlExporter.WsdlNamingHelper.GetPortTypeQName(cd);
                if (qnames.Contains(qname))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxMetadataResolverKnownContractsUniqueQNames, qname.Name, qname.Namespace));
                }
 
                qnames.Add(qname);
            }
 
            if (isEmpty)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFxMetadataResolverKnownContractsArgumentCannotBeEmpty));
            }
        }
 
        private static Collection<ContractDescription> CreateContractCollection(Type contract)
        {
            Collection<ContractDescription> contracts = new Collection<ContractDescription>();
            contracts.Add(ContractDescription.GetContract(contract));
            return contracts;
        }
    }
}