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)
{ }
}
}