using System;
using System.Collections.Generic;
namespace Developpez.Dotnet.Windows.Service
{
///
/// Fournit un accès global à un ensemble de services via leur interface et éventuellement leur nom
///
public sealed class ServiceLocator : IServiceProvider
{
#region Private data
private readonly Dictionary> _services;
#endregion
#region Constructor
private ServiceLocator()
{
_services = new Dictionary>();
}
#endregion
#region Singleton implementation
private readonly static ServiceLocator _instance;
static ServiceLocator()
{
_instance = new ServiceLocator();
}
///
/// Renvoie l'unique instance de la classe ServiceLocator
///
public static ServiceLocator Instance
{
get { return _instance; }
}
#endregion
#region RegisterService methods
///
/// Inscrit un service en spécifiant le type de l'interface, le nom du service et l'objet qui implémente le service.
///
/// Interface du service
/// Nom du service
/// Implémentation du service
public void RegisterService(Type serviceType, string name, object service)
{
lock (_services)
{
var services = GetServicesForType(serviceType, true);
services.Add(name ?? string.Empty, service);
}
}
///
/// Inscrit un service en spécifiant le type de l'interface et l'objet qui implémente le service.
/// Le nom utilisé pour le service est une chaine vide.
///
/// Interface du service
/// Implémentation du service
public void RegisterService(Type serviceType, object service)
{
RegisterService(serviceType, string.Empty, service);
}
///
/// Inscrit un service en spécifiant le type de l'interface, le nom du service et l'objet qui implémente le service.
///
/// Interface du service
/// Nom du service
/// Implémentation du service
public void RegisterService(string name, T service)
{
RegisterService(typeof(T), name, service);
}
///
/// Inscrit un service en spécifiant le type de l'interface et l'objet qui implémente le service.
/// Le nom utilisé pour le service est une chaine vide.
///
/// Interface du service
/// Implémentation du service
public void RegisterService(T service)
{
RegisterService(typeof(T), string.Empty, service);
}
#endregion
#region GetService methods
///
/// Obtient un service d'après son interface et son nom.
///
/// Interface du service
/// Nom du service
/// Le service spécifié s'il existe. Sinon, lève une ServiceNotFoundException
public object GetService(Type serviceType, string name)
{
var service = GetServiceInternal(serviceType, name);
if (service == null)
throw new ServiceNotFoundException(serviceType, name, string.Format("No service registered for type '{0}' and name '{1}'", serviceType.FullName, name));
return service;
}
///
/// Obtient un service sans nom d'après son interface.
///
/// Interface du service
/// Le service spécifié s'il existe. Sinon, lève une ServiceNotFoundException
public object GetService(Type serviceType)
{
return GetService(serviceType, string.Empty);
}
///
/// Obtient un service d'après son interface et son nom.
///
/// Interface du service
/// Nom du service
/// Le service spécifié s'il existe. Sinon, lève une ServiceNotFoundException
public T GetService(string name)
{
return (T)GetService(typeof(T), name);
}
///
/// Obtient un service sans nom d'après son interface.
///
/// Interface du service
/// Le service spécifié s'il existe. Sinon, lève une ServiceNotFoundException
public T GetService()
{
return (T)GetService(typeof(T), string.Empty);
}
///
/// Implémente explicitement l'interface IServiceProvider. Equivalent à
/// ServiceLocator.GetService(Type), mais renvoie null si le service n'est
/// pas trouvé au lieu de lever une exception.
///
/// Interface du service
/// Le service demandé s'il existe, sinon null
object IServiceProvider.GetService(Type serviceType)
{
return GetServiceInternal(serviceType, string.Empty);
}
#endregion
#region Private methods
private Dictionary GetServicesForType(Type serviceType, bool create)
{
lock (_services)
{
Dictionary services;
if (!_services.TryGetValue(serviceType, out services))
{
if (create)
{
services = new Dictionary();
_services[serviceType] = services;
}
}
return services;
}
}
private object GetServiceInternal(Type serviceType, string name)
{
lock (_services)
{
var services = GetServicesForType(serviceType, false);
if (services != null)
{
object service;
services.TryGetValue(name ?? string.Empty, out service);
return service;
}
return null;
}
}
#endregion
}
///
/// Exception levée quand le ServiceLocator ne trouve pas le service demandé
///
[Serializable]
public class ServiceNotFoundException : Exception
{
private readonly Type _serviceType;
private readonly string _serviceName;
///
/// Type du service demandé
///
public Type ServiceType
{
get { return _serviceType; }
}
///
/// Nom du service demandé
///
public string ServiceName
{
get { return _serviceName; }
}
///
/// Initialise une nouvelle instance de ServiceNotFoundException avec le message par défaut
///
/// Type du service demandé
public ServiceNotFoundException(Type serviceType)
: this(serviceType, string.Empty)
{
}
///
/// Initialise une nouvelle instance de ServiceNotFoundException avec le message par défaut
///
/// Type du service demandé
/// Nom du service demandé
public ServiceNotFoundException(Type serviceType, string serviceName)
{
_serviceType = serviceType;
_serviceName = serviceName;
}
///
/// Initialise une nouvelle instance de ServiceNotFoundException avec le message spécifié
///
/// Type du service demandé
/// Nom du service demandé
/// Message de l'exception
public ServiceNotFoundException(Type serviceType, string serviceName, string message)
: base(message)
{
_serviceType = serviceType;
_serviceName = serviceName;
}
///
/// Initialise une nouvelle instance de ServiceNotFoundException avec le message et l'exception interne spécifiés
///
/// Type du service demandé
/// Nom du service demandé
/// Message de l'exception
/// Exception interne
public ServiceNotFoundException(Type serviceType, string serviceName, string message, Exception inner)
: base(message, inner)
{
_serviceType = serviceType;
_serviceName = serviceName;
}
///
/// Initialise une nouvelle instance de ServiceNotFoundException à partir de données sérialisées.
///
/// SerializationInfo qui contient les données d'objet sérialisées relatives à l'exception levée.
/// StreamingContext qui contient des informations contextuelles sur la source ou la destination.
protected ServiceNotFoundException(
System.Runtime.Serialization.SerializationInfo info,
System.Runtime.Serialization.StreamingContext context)
: base(info, context) { }
}
}