Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Integrating WCF Services into UDDI based enterprise SOA

, 27 Jan 2009 CPOL
Shows how to integrate WCF services into a UDDI based SOA. This includes the discovery of WCF services at runtime and the runtime configuration of the client.
DynamicWCFFactory.zip
DynamicWCFFactory
DynamicWCFFactory
Behaviours
bin
Debug
Configuration
Properties
DynamicWCFFactory.gpState
DynamicWCFFactory.vsmdi
DynamicWCFFactoryTests
bin
Debug
Properties
Service References
ServiceReference
configuration.svcinfo
configuration91.svcinfo
DynamicWCFFactoryTests.ServiceReference.CompositeType.datasource
Reference.svcmap
Service1.disco
Service1.wsdl
LocalTestRun.testrunconfig
TestResults
UDDIServiceFactory
bin
Debug
Configuration
Lib
Microsoft.Uddi.dll
Properties
WcfService
App_Data
bin
Properties
Service1.svc
WcfService.csproj.user
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Description;
using System.ServiceModel;
using DynamicWCFFactory;
using System.Configuration;
using DynamicWCFFactory.Behaviors;
using Microsoft.Practices.EnterpriseLibrary.Logging;

namespace DynamicWCFFactory
{
    /// <summary>
    /// Discovers a service on its /mex or ?WSDL endpoint and creates a proxy
    /// </summary>
    /// <typeparam name="TClient">The type of the WCF client e.g. SCDServiceClient</typeparam>
    /// <typeparam name="TServiceInterface">The ServiceInterface</typeparam>
    public class DynamicWCFFactory<TClient, TServiceInterface>
        where TClient : class
        where TServiceInterface : class
    {
        /// <summary>
        /// Region for the ErrorIDS
        /// </summary>
        #region ERROR_IDS
        const int ERROR_MEX_FAILURE = 600;
        const int ERROR_WSDL_FAILURE = 601;
        const int ERROR_MDS_FAILURE = 602;
        #endregion

        #region Properties
        public int BindingID
        {    get; set; }
        #endregion

        #region PrivateMethods

        /// <summary>
        /// Instantiates a new Proxy by endpoint
        /// </summary>
        /// <typeparam name="ServiceType">The service client type</typeparam>
        /// <typeparam name="ServiceInterface">Service Interface Type</typeparam>
        /// <param name="CallbackInstance">Callback Instance for Duplex Bindings</param>
        /// <param name="endpoint">The endpoint for the proxy</param>
        /// <returns>An instance of ClientType</returns>
        private static TClient ActivateProxy(object CallbackInstance, ServiceEndpoint endpoint)
        {
            if (typeof(TClient) is DuplexClientBase<TServiceInterface>)   // DuplexClientBase
                return Activator.CreateInstance(typeof(TClient), new object[] { new InstanceContext(CallbackInstance), endpoint.Binding, endpoint.Address }) as TClient;
            else
                return Activator.CreateInstance(typeof(TClient), new object[] { endpoint.Binding, endpoint.Address }) as TClient;
         
        }

        /// <summary>
        /// Instantiates a new Proxy by Endpoint Adress and applies endpoint configuration from configuration file
        /// </summary>
        /// <typeparam name="ServiceType">The service client type</typeparam>
        /// <typeparam name="ServiceInterface">Service Interface Type</typeparam>
        /// <param name="CallbackInstance">Callback Instance for Duplex Bindings</param>
        /// <param name="endPointConfig">The name for the endpoint configuration in config file</param>
        /// <param name="endPointAdress">Address of service endpoint</param>
        /// <returns></returns>
        private static TClient ActivateProxy(object CallbackInstance, string endPointConfig, string endPointAdress) 
        {
            if (typeof(TClient) is DuplexClientBase<TServiceInterface>)   // DuplexClientBase
                return Activator.CreateInstance(typeof(TClient), new object[] { new InstanceContext(CallbackInstance), endPointConfig, endPointAdress }) as TClient;
            else
                return Activator.CreateInstance(typeof(TClient), new object[] { endPointConfig, endPointAdress }) as TClient;
        }

        /// <summary>
        /// Selects the best endpoint
        /// </summary>
        /// <param name="endpoints">The endpoint collection to choose from</param>
        /// <returns>the endpoint of choice</returns>
        private ServiceEndpoint ChooseBestEndPoint(ServiceEndpointCollection endpoints)
        {
            if (BindingID < endpoints.Count)
                return endpoints[BindingID];
            else
                return endpoints[0];
        }

        /// <summary>
        /// Tries to read the service WSDL either at /mex (POST) endpoint or at the ?WSDL (GET) url if it is http
        /// </summary>
        /// <param name="serviceURL">The URL of the Service</param>
        /// <returns>the collection endpoints offered by the Service</returns>
        private ServiceEndpointCollection DiscoverServiceEndpoints(string serviceURL)
        {
            MetadataSet mds = null;
            WSHttpBinding binding = new System.ServiceModel.WSHttpBinding(System.ServiceModel.SecurityMode.None);
            binding.MaxReceivedMessageSize = int.MaxValue;
            MetadataExchangeClient mexClient = new System.ServiceModel.Description.MetadataExchangeClient(binding);

            // First try to query the mex endpoint
            try
            {
                mds = mexClient.GetMetadata(new System.ServiceModel.EndpointAddress(serviceURL + "/mex"));
            }
            catch (InvalidOperationException ex)
            {
                if ((ConfigurationManager.GetSection("loggingConfiguration") != null) && (Logger.IsLoggingEnabled()))
                    Logger.Write(ex, new List<string> { "General" }, 1, ERROR_MEX_FAILURE, System.Diagnostics.TraceEventType.Warning, "Connection to Mex Endpoint using WSHTTPBinding has failed");
            }

            // If not succesful try to query the ?WSDL adress if it is a http based service
            if ((mds == null) && (new Uri(serviceURL).Scheme == "http"))
                try
                {
                    mds = mexClient.GetMetadata(new Uri(serviceURL + "?WSDL"),MetadataExchangeClientMode.HttpGet);

                }
                catch (InvalidOperationException ex)
                {
                    if ((ConfigurationManager.GetSection("loggingConfiguration") != null) && (Logger.IsLoggingEnabled()))
                        Logger.Write(ex, new List<string> { "General" }, 1, ERROR_WSDL_FAILURE, System.Diagnostics.TraceEventType.Error, "Connection to ?WSDL URL  using WSHTTPBinding has failed. MetadataExchangeClient failed");
                    throw new ConfigurationErrorsException("MetadataExchangeClient failed with: " + ex.Message, ex);
                }

            // Verify we got a ServiceDescription Section


            if (mds.MetadataSections.Count(section => section.Metadata is System.Web.Services.Description.ServiceDescription) < 1)
            {
                if ((ConfigurationManager.GetSection("loggingConfiguration") != null) && (Logger.IsLoggingEnabled()))
                    Logger.Write("Metadataset contains no service description. Maybe it is not a service?", new List<string> { "General" }, 1, ERROR_MDS_FAILURE, System.Diagnostics.TraceEventType.Error, "Metadataset contains no service description. Maybe it is not a service?");
                throw new ConfigurationErrorsException("Metadata does not contain a service description");
            }

            WsdlImporter importer = new WsdlImporter(mds);

            return importer.ImportAllEndpoints();
        }
        

        #endregion

        #region PublicMethods

        /// <summary>
        /// Creates a Proxy from Service URL and name of the Endpoint configuration in config file
        /// </summary>
        /// <typeparam name="ServiceType">The service client type</typeparam>
        /// <typeparam name="ServiceInterface">Service Interface Type</typeparam>
        /// <param name="serviceURL">The URL of the service</param>
        /// <param name="endpointConfig">The name of the endpoint configuration in configuration file</param>
        /// <returns>a new client</returns>
        public TClient CreateProxyFromWSDL(string serviceURL,string endpointConfig) 
        {
            return CreateProxyFromWSDL(serviceURL,null,endpointConfig);
        }
        
        
        /// <summary>
        /// Creates a Duplex capable Proxy from Service URL and name of the Endpoint configuration in config file 
        /// </summary>
        /// <typeparam name="ServiceType">The service client type</typeparam>
        /// <typeparam name="ServiceInterface">Service Interface Type</typeparam>
        /// <param name="serviceURL">The URL of the service</param>
        /// <param name="CallbackInstance">The CallbackInstance for Duplex</param>
        /// <param name="endpointConfig">The name of the endpoint configuration in configuration file</param>
        /// <returns>a new client</returns>
        public TClient CreateProxyFromWSDL(string serviceURL, object CallbackInstance,string endpointConfig) 
        {
            ServiceEndpoint endpoint = ChooseBestEndPoint(DiscoverServiceEndpoints(serviceURL));

            return ActivateProxy(CallbackInstance, endpointConfig,endpoint.Address.Uri.ToString());
        }

        /// <summary>
        /// Creates a new Proxy from ServiceURL and custom configuration properties
        /// </summary>
        /// <typeparam name="ServiceType">The service client type</typeparam>
        /// <typeparam name="ServiceInterface">Service Interface Type</typeparam>
        /// <param name="serviceURL">The URL of the service</param>
        /// <param name="properties">The configuration properties</param>
        /// <returns>a new client</returns>
        public TClient CreateProxyFromWSDL(string serviceURL,BindingConfigurationHelper.BindingProperties properties) 
        {
            return CreateProxyFromWSDL(serviceURL,null,properties);
        }

        /// <summary>
        /// Creates a new Proxy from ServiceURL 
        /// </summary>
        /// <typeparam name="ServiceType">The service client type</typeparam>
        /// <typeparam name="ServiceInterface">Service Interface Type</typeparam>
        /// <param name="serviceURL">The URL of the service</param>
        /// <returns>a new client</returns>
        public TClient CreateProxyFromWSDL(string serviceURL)
        {
            return CreateProxyFromWSDL(serviceURL, null, null as BindingConfigurationHelper.BindingProperties);
        }

        /// <summary>
        /// Creates a new duplex capable Proxy from ServiceURL
        /// </summary>
        /// <typeparam name="ServiceType">The service client type</typeparam>
        /// <typeparam name="ServiceInterface">Service Interface Type</typeparam>
        /// <param name="serviceURL">The URL of the service</param>
        /// <param name="CallbackInstance">The CallbackInstance for Duplex</param>
        /// <returns>a new client</returns>
        public TClient CreateProxyFromWSDL(string serviceURL, object CallBackInstance)
        {
            return CreateProxyFromWSDL(serviceURL, CallBackInstance, null as BindingConfigurationHelper.BindingProperties);
        }

        /// <summary>
        /// Creates a new duplex capable Proxy from ServiceURL. Applies Default parameters if "UseBindingDefaults" appsetting is set to "1" in config file
        /// </summary>
        /// <typeparam name="ServiceType">The service client type</typeparam>
        /// <typeparam name="ServiceInterface">Service Interface Type</typeparam>
        /// <param name="serviceURL">The URL of the service</param>
        /// <param name="CallbackInstance">The CallbackInstance for Duplex</param>
        /// <param name="properties">The custom configuration properties</param>
        /// <returns>a new client</returns>
        public TClient CreateProxyFromWSDL(string serviceURL,object CallbackInstance,BindingConfigurationHelper.BindingProperties properties)
        {
            ServiceEndpoint endpoint = ChooseBestEndPoint(DiscoverServiceEndpoints(serviceURL));

            if (ConfigurationManager.AppSettings["UseBindingDefaults"] == "1")
            {
                if (properties == null)
                    properties = new BindingConfigurationHelper.BindingProperties();

                properties.Add("MaxReceivedMessageSize", int.MaxValue);
                properties.Add("MaxBufferSize", int.MaxValue);
                properties.Add("MaxItemsInObjectGraph", int.MaxValue);
            }

            if (properties != null)
            {
                BindingConfigurationHelper myHelper = new BindingConfigurationHelper();
                myHelper.ConfigureClientBinding(endpoint.Binding,properties);
            }

            TClient ret_obj =  ActivateProxy(CallbackInstance,endpoint);
            
            if ((properties!=null) && (properties.ContainsKey("MaxItemsInObjectGraph") && ret_obj != null))
                if ((ret_obj as ClientBase<TServiceInterface>).Endpoint.Behaviors.Find<CustomDataContractSerializerOperationBehavior>() == null)
                    (ret_obj as ClientBase<TServiceInterface>).ChannelFactory.Endpoint.Behaviors.Add(new CustomDataContractSerializerOperationBehavior() { MaxItemsInObjectGraph = Convert.ToInt32(properties["MaxItemsInObjectGraph"]) });
            

            
            return ret_obj;
        }

        #endregion

    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Tobias Manthey
Architect
Germany Germany
being IT-Engineer since 1995 I am freelancing since then. From networks to programming, from system administration to DBA, from AIX to Windows I offer a wide range of IT-Skill's without considering me the ultimate expert in each area.
I try to avoid complexity wherever I can and so my philosophy is to strictly follow KISS principles.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411023.1 | Last Updated 27 Jan 2009
Article Copyright 2009 by Tobias Manthey
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid