Click here to Skip to main content
15,867,835 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 68.9K   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 Microsoft.Uddi;
using Microsoft.Uddi.Extensions;
using UDDIServiceFactory.Configuration;
using System.Configuration;
using Microsoft.Practices.EnterpriseLibrary.Logging;
using DynamicWCFFactory;
using System.ServiceModel;

namespace UDDIServiceFactory
{
    
    /// <summary>
    /// UDDIServiceFactory connects to UDDI and dynamically creates Clients using DynamicWCFFactory
    /// </summary>
    /// <typeparam name="TClient">The type of proxy e.g. SCDServiceClient</typeparam>
    /// <typeparam name="TServiceInterface">The type of ServiceInterface e.g. ISCDService</typeparam>
    public class UDDIServiceFactory<TClient, TServiceInterface>
        where TClient : ClientBase<TServiceInterface>, new()
        where TServiceInterface : class
    {

        #region constants
        const int ERROR_UDDI_CONNECTION = 500;
        const int ERROR_SERVICE_FAILURE = 501;
        const int ID_FAIL_SAFE = 502;
        const int ERROR_CACHED_CLIENT_CLOSED = 503;
        #endregion


        #region Privates
        /// <summary>
        /// The ManagedURL filled from UDDI. Keeps connection to UDDI all the time!
        /// </summary>
        ManagedUrl _managedURL = null;
        /// <summary>
        /// The failcount
        /// </summary>
        int _failCount = 0;
        /// <summary>
        /// The Custom Binding parameter to configure our binding
        /// </summary>
        DynamicWCFFactory.BindingConfigurationHelper.BindingProperties _properties;
        /// <summary>
        /// The URL to the last succesfully created client (used for caching)
        /// </summary>
        string _lastServiceURL;
        /// <summary>
        /// The last succesfully created client (used for caching)
        /// </summary>
        TClient _lastProxy;
        
        #endregion

        #region Ctors

        /// <summary>
        /// Initializes UDDIServiceFactory with a configurationsection
        /// </summary>
        /// <param name="configurationSectionName">Name of ServiceDiscoveryConfigurationSection</param>
        public UDDIServiceFactory(string configurationSectionName) : this(configurationSectionName,null)
        {
        }

        /// <summary>
        /// Initializes UDDIServiceFactory with a configurationsection and custom bindingparameters
        /// </summary>
        /// <param name="configurationSectionName">Name of ServiceDiscoveryConfigurationSection</param>
        /// <param name="properties">The Bindingpropierties used for </param>
        public UDDIServiceFactory(string configurationSectionName,DynamicWCFFactory.BindingConfigurationHelper.BindingProperties properties)
        {
            _properties = properties;

            ServiceDiscoveryConfigurationHelper helper = new ServiceDiscoveryConfigurationHelper();
            // Retrieve the configuration section from the config file.
            ServiceDiscoveryConfigurationSection section = helper.Section(configurationSectionName);

            // If the returned configuration section is null.
            if (null == section)
            {
                // Throw an exception to let the caller know about the problem.
                throw new ConfigurationErrorsException(string.Format("No configuration section named '{0}' could be found.", configurationSectionName));
            }

            RetrieveUDDIManagedURL(section.DirectoryURL, section.ServiceKey, section.TModelKey);


        }
        
        /// <summary>
        /// Initializes UDDIServiceFactory 
        /// </summary>
        /// <param name="UDDIUrl">The URL to the UDDI e.g. http://myServer.myDomain.com/uddi/</param>
        /// <param name="serviceKey">The Key of the Service as from UDDI</param>
        /// <param name="modelKey">the TModelKey as from UDDI</param>
        public UDDIServiceFactory(string UDDIUrl, string serviceKey, string modelKey)
            : this(UDDIUrl, serviceKey, modelKey, null)
        { }

        public UDDIServiceFactory(string UDDIUrl, string serviceKey, string modelKey, DynamicWCFFactory.BindingConfigurationHelper.BindingProperties properties)
        {
            _properties = properties;

            RetrieveUDDIManagedURL(UDDIUrl, serviceKey, modelKey);

        }

        /// <summary>
        /// Retrieves the ManagedURL
        /// </summary>
        /// <param name="UDDIUrl">The URL to the UDDI e.g. http://myServer.myDomain.com/uddi/</param>
        /// <param name="serviceKey">The Key of the Service as from UDDI</param>
        /// <param name="modelKey">the TModelKey as from UDDI</param>
        private void RetrieveUDDIManagedURL(string UDDIUrl, string serviceKey, string modelKey)
        {
            try
            {
                _managedURL = RetrieveManagedUrl(UDDIUrl, serviceKey, modelKey);
                if (ConfigurationManager.AppSettings["LoadBalaceUDDIServices"] == "1")
                {
                    Random rand = new Random();
                    int serviceNo = rand.Next(0, _managedURL.Count );
                    for (int i = 0; i < serviceNo; i++)
                        _managedURL.FailOver();
                }
                
            }
            catch (Exception ex)
            {
                if ((ConfigurationManager.GetSection("loggingConfiguration") != null) && (Logger.IsLoggingEnabled()))
                    Logger.Write(ex, new string[] { "General" }, 1, ERROR_UDDI_CONNECTION, System.Diagnostics.TraceEventType.Error, "Can not connect to UDDI");
            }
        }

        #endregion

        #region Methods
        /// <summary>
        /// Creates a Proxy by discovering it through its WSDL
        /// </summary>
        /// <param name="CallBackInstance">Optional Parameter to a CallBackInstance for DuplexChannels</param>
        /// <returns>A Proxy</returns>
        private TClient GetProxy(object CallBackInstance) 
        {
            int ServiceCount = _managedURL == null ? 0 : _managedURL.Count;
            
            while (true)
            {
                if ((_failCount == ServiceCount) && (ConfigurationManager.AppSettings["ReturnDefaultClient"] == "1"))
                {
                    if ((ConfigurationManager.GetSection("loggingConfiguration") != null) && (Logger.IsLoggingEnabled()))
                        Logger.Write("UDDI Service resolution failed. Emergency failsafe to default client", new string[] { "General" }, 1, ID_FAIL_SAFE, System.Diagnostics.TraceEventType.Error);
                    return new TClient();
                }
                else if (_failCount < ServiceCount)
                {
                    try
                    {
                        var dynWCFFactory = new DynamicWCFFactory.DynamicWCFFactory<TClient,TServiceInterface>();
                        return dynWCFFactory.CreateProxyFromWSDL(_managedURL.Value, CallBackInstance, _properties);
                    }
                    catch (Exception ex)
                    {
                        if ((ConfigurationManager.GetSection("loggingConfiguration") != null) && (Logger.IsLoggingEnabled()))
                            Logger.Write(ex, new string[] { "General" }, 1, ERROR_SERVICE_FAILURE, System.Diagnostics.TraceEventType.Warning, "Connection to UDDI Registered Service failed");
                    }
                }
                else if (_failCount >= ServiceCount)
                    throw new UDDIServiceFactoryException("Can not connect to any service. Giving up. See Errorlog for Details");

                _managedURL.FailOver();
                _failCount++;

            }
        }

        /// <summary>
        /// Retrieves a ManagedURL from UDDI. Remember the ManagedURL keeps connection to the UDDI
        /// </summary>
        /// <param name="UDDIUrl">The URL to the UDDI e.g. http://myServer.myDomain.com/uddi/</param>
        /// <param name="serviceKey">The Key of the Service as from UDDI</param>
        /// <param name="modelKey">the TModelKey as from UDDI</param>
        /// <returns>A managed URL object</returns>
        private ManagedUrl RetrieveManagedUrl(string uDDIURL,string serviceKey,string modelKey )
        {
            // Create UDDI location object
            UddiSiteLocation _siteLocation = new UddiSiteLocation(uDDIURL + "inquire.asmx",
                uDDIURL + "publish.asmx",
                uDDIURL + "extension.asmx",
                string.Empty,
                Microsoft.Uddi.AuthenticationMode.WindowsAuthentication);

            // Initialize a new instance of the FindBinding class used to locate the service.
            // Add the service key to the binding.
            FindBinding _findBinding = new FindBinding(modelKey);
            _findBinding.ServiceKey = serviceKey;

            // Create the managed URL object. It is dynamically updated by the UDDI Registry
            UddiConnection _connection = new UddiConnection(_siteLocation);
            return _managedURL = new ManagedUrl(_connection, _findBinding);
        }

        /// <summary>
        /// Resets the error count and returns the first working proxy
        /// </summary>
        /// <returns>A new client proxy</returns>
        public TClient GetFirstProxy()
        {
            return GetFirstProxy(null);
        }

        /// <summary>
        /// Resets the error count and returns the first working proxy
        /// </summary>
        /// <param name="CallBackInstance">Optional Parameter to a CallBackInstance for DuplexChannels</param>
        /// <returns>A new client proxy</returns>
        public TClient GetFirstProxy(object CallBackInstance)
        {
            _failCount = 0;
            // Some cautious Caching to improve performance

            if ((_lastProxy == null) && (_managedURL != null)) // First Call since class was instantiated
            {
                _lastProxy = GetProxy(CallBackInstance);
                _lastServiceURL = _managedURL.Value;
                return _lastProxy;
            }
            else if ((_managedURL != null) && (_managedURL.Value == _lastServiceURL)) // we are requested to return the client we disovered last time
            {
                if (_lastProxy.State != CommunicationState.Opened)
                {
                    if ((ConfigurationManager.GetSection("loggingConfiguration") != null) && (Logger.IsLoggingEnabled()))
                        Logger.Write("Cached Client is not open. Need to create new client. Did you call Close() too early?", new string[] { "General" }, 1, ERROR_CACHED_CLIENT_CLOSED, System.Diagnostics.TraceEventType.Warning, "Cached client in closed state");
                    _lastProxy = GetProxy(CallBackInstance);
                    _lastServiceURL = _managedURL.Value;
                    return _lastProxy;
                }
                else
                    return _lastProxy;  // return the cached proxy. It is open
            }
            else
                return GetProxy(CallBackInstance);
        }

        /// <summary>
        /// Increases the error count and returns the next proxy 
        /// </summary>
        /// <param name="CallBackInstance">Optional Parameter to a CallBackInstance for DuplexChannels</param>
        /// <returns>A new client proxy</returns>
        public TClient GetNextProxy(object CallBackInstance)
        {
            _failCount++;

            if (_managedURL != null)
                _managedURL.FailOver();

            _lastProxy = GetProxy(CallBackInstance);
            
            _lastServiceURL = _managedURL == null ? string.Empty : _managedURL.Value;

            return _lastProxy;
        }

        public TClient GetNextProxy()
        {
            return GetNextProxy(null);
        }

        #endregion

    }
    /// <summary>
    /// Exception in case we can not create a proxy
    /// </summary>
    class UDDIServiceFactoryException : Exception
    {
        public UDDIServiceFactoryException(string message)
            : base(message)
        { }
    }
}

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