Click here to Skip to main content
15,881,516 members
Articles / Programming Languages / C#

Integrating WCF Services into UDDI based enterprise SOA

Rate me:
Please Sign up or sign in to vote.
4.87/5 (16 votes)
27 Jan 2009CPOL18 min read 69K   749   42  
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.
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)


Written By
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.

Comments and Discussions