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