The Labs \ Source Viewer \ SSCLI \ System.ComponentModel.Design \ ServiceContainer

  1. //------------------------------------------------------------------------------
  2. // <copyright file="ServiceObjectContainer.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. /*
  16. */
  17. namespace System.ComponentModel.Design
  18. {
  19.     using Microsoft.Win32;
  20.     using System;
  21.     using System.Collections;
  22.     using System.Diagnostics;
  23.     using System.Security.Permissions;
  24.    
  25.     /// <devdoc>
  26.     /// This is a simple implementation of IServiceContainer.
  27.     /// </devdoc>
  28.     [HostProtection(SharedState = true)]
  29.     public class ServiceContainer : IServiceContainer, IDisposable
  30.     {
  31.         private Hashtable services;
  32.         private IServiceProvider parentProvider;
  33.         private static Type[] _defaultServices = new Type[] {typeof(IServiceContainer), typeof(ServiceContainer)};
  34.        
  35.         private static TraceSwitch TRACESERVICE = new TraceSwitch("TRACESERVICE", "ServiceProvider: Trace service provider requests.");
  36.        
  37.         /// <devdoc>
  38.         /// Creates a new service object container.
  39.         /// </devdoc>
  40.         public ServiceContainer()
  41.         {
  42.         }
  43.        
  44.         /// <devdoc>
  45.         /// Creates a new service object container.
  46.         /// </devdoc>
  47.         public ServiceContainer(IServiceProvider parentProvider)
  48.         {
  49.             this.parentProvider = parentProvider;
  50.         }
  51.        
  52.         /// <devdoc>
  53.         /// Retrieves the parent service container, or null
  54.         /// if there is no parent container.
  55.         /// </devdoc>
  56.         private IServiceContainer Container {
  57.             get {
  58.                 IServiceContainer container = null;
  59.                 if (parentProvider != null) {
  60.                     container = (IServiceContainer)parentProvider.GetService(typeof(IServiceContainer));
  61.                 }
  62.                 return container;
  63.             }
  64.         }
  65.        
  66.         /// <devdoc>
  67.         /// This property returns the default services that are implemented directly on this IServiceContainer.
  68.         /// the default implementation of this property is to return the IServiceContainer and ServiceContainer
  69.         /// types. You may override this proeprty and return your own types, modifying the default behavior
  70.         /// of GetService.
  71.         /// </devdoc>
  72.         protected virtual Type[] DefaultServices {
  73.             get { return _defaultServices; }
  74.         }
  75.        
  76.         /// <devdoc>
  77.         /// Our hashtable of services. The hashtable is demand
  78.         /// created here.
  79.         /// </devdoc>
  80.         private Hashtable Services {
  81.             get {
  82.                 if (services == null) {
  83.                     services = new Hashtable();
  84.                 }
  85.                 return services;
  86.             }
  87.         }
  88.        
  89.         /// <devdoc>
  90.         /// Adds the given service to the service container.
  91.         /// </devdoc>
  92.         public void AddService(Type serviceType, object serviceInstance)
  93.         {
  94.             AddService(serviceType, serviceInstance, false);
  95.         }
  96.        
  97.         /// <devdoc>
  98.         /// Adds the given service to the service container.
  99.         /// </devdoc>
  100.         public virtual void AddService(Type serviceType, object serviceInstance, bool promote)
  101.         {
  102.             Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Adding service (instance) " + serviceType.Name + ". Promoting: " + promote.ToString());
  103.             if (promote) {
  104.                 IServiceContainer container = Container;
  105.                 if (container != null) {
  106.                     Debug.Indent();
  107.                     Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Promoting to container");
  108.                     Debug.Unindent();
  109.                     container.AddService(serviceType, serviceInstance, promote);
  110.                     return;
  111.                 }
  112.             }
  113.            
  114.             // We're going to add this locally. Ensure that the service instance
  115.             // is correct.
  116.             //
  117.             if (serviceType == null)
  118.                 throw new ArgumentNullException("serviceType");
  119.             if (serviceInstance == null)
  120.                 throw new ArgumentNullException("serviceInstance");
  121.             if (!(serviceInstance is ServiceCreatorCallback) && !serviceInstance.GetType().IsCOMObject && !serviceType.IsAssignableFrom(serviceInstance.GetType())) {
  122.                 throw new ArgumentException(SR.GetString(SR.ErrorInvalidServiceInstance, serviceType.FullName));
  123.             }
  124.            
  125.             if (Services.ContainsKey(serviceType)) {
  126.                 throw new ArgumentException(SR.GetString(SR.ErrorServiceExists, serviceType.FullName), "serviceType");
  127.             }
  128.            
  129.             Services[serviceType] = serviceInstance;
  130.         }
  131.        
  132.         /// <devdoc>
  133.         /// Adds the given service to the service container.
  134.         /// </devdoc>
  135.         public void AddService(Type serviceType, ServiceCreatorCallback callback)
  136.         {
  137.             AddService(serviceType, callback, false);
  138.         }
  139.        
  140.         /// <devdoc>
  141.         /// Adds the given service to the service container.
  142.         /// </devdoc>
  143.         public virtual void AddService(Type serviceType, ServiceCreatorCallback callback, bool promote)
  144.         {
  145.             Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Adding service (callback) " + serviceType.Name + ". Promoting: " + promote.ToString());
  146.             if (promote) {
  147.                 IServiceContainer container = Container;
  148.                 if (container != null) {
  149.                     Debug.Indent();
  150.                     Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Promoting to container");
  151.                     Debug.Unindent();
  152.                     container.AddService(serviceType, callback, promote);
  153.                     return;
  154.                 }
  155.             }
  156.            
  157.             // We're going to add this locally. Ensure that the service instance
  158.             // is correct.
  159.             //
  160.             if (serviceType == null)
  161.                 throw new ArgumentNullException("serviceType");
  162.             if (callback == null)
  163.                 throw new ArgumentNullException("callback");
  164.            
  165.             if (Services.ContainsKey(serviceType)) {
  166.                 throw new ArgumentException(SR.GetString(SR.ErrorServiceExists, serviceType.FullName), "serviceType");
  167.             }
  168.            
  169.             Services[serviceType] = callback;
  170.         }
  171.        
  172.         /// <devdoc>
  173.         /// Disposes this service container. This also walks all instantiated services within the container
  174.         /// and disposes any that implement IDisposable, and clears the service list.
  175.         /// </devdoc>
  176.         public void Dispose()
  177.         {
  178.             Dispose(true);
  179.         }
  180.        
  181.         /// <devdoc>
  182.         /// Disposes this service container. This also walks all instantiated services within the container
  183.         /// and disposes any that implement IDisposable, and clears the service list.
  184.         /// </devdoc>
  185.         protected virtual void Dispose(bool disposing)
  186.         {
  187.             if (disposing) {
  188.                 Hashtable serviceHash = services;
  189.                 services = null;
  190.                 if (serviceHash != null) {
  191.                     foreach (object o in serviceHash.Values) {
  192.                         if (o is IDisposable) {
  193.                             ((IDisposable)o).Dispose();
  194.                         }
  195.                     }
  196.                 }
  197.             }
  198.         }
  199.        
  200.         /// <devdoc>
  201.         /// Retrieves the requested service.
  202.         /// </devdoc>
  203.         public virtual object GetService(Type serviceType)
  204.         {
  205.             object service = null;
  206.            
  207.             Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Searching for service " + serviceType.Name);
  208.             Debug.Indent();
  209.            
  210.             // Try locally. We first test for services we
  211.             // implement and then look in our hashtable.
  212.             //
  213.             Type[] defaults = DefaultServices;
  214.             for (int idx = 0; idx < defaults.Length; idx++) {
  215.                 if (serviceType == defaults[idx]) {
  216.                     service = this;
  217.                     break;
  218.                 }
  219.             }
  220.            
  221.             if (service == null) {
  222.                 service = Services[serviceType];
  223.             }
  224.            
  225.             // Is the service a creator delegate?
  226.             //
  227.             if (service is ServiceCreatorCallback) {
  228.                 Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Encountered a callback. Invoking it");
  229.                 service = ((ServiceCreatorCallback)service)(this, serviceType);
  230.                 Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Callback return object: " + (service == null ? "(null)" : service.ToString()));
  231.                 if (service != null && !service.GetType().IsCOMObject && !serviceType.IsAssignableFrom(service.GetType())) {
  232.                     // Callback passed us a bad service. NULL it, rather than throwing an exception.
  233.                     // Callers here do not need to be prepared to handle bad callback implemetations.
  234.                     Debug.Fail("Object " + service.GetType().Name + " was returned from a service creator callback but it does not implement the registered type of " + serviceType.Name);
  235.                     Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "**** Object does not implement service interface");
  236.                     service = null;
  237.                 }
  238.                
  239.                 // And replace the callback with our new service.
  240.                 //
  241.                 Services[serviceType] = service;
  242.             }
  243.            
  244.             if (service == null && parentProvider != null) {
  245.                 Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Service unresolved. Trying parent");
  246.                 service = parentProvider.GetService(serviceType);
  247.             }
  248.            
  249.             #if DEBUG
  250.             if (TRACESERVICE.TraceVerbose && service == null) {
  251.                 Debug.WriteLine("******************************************");
  252.                 Debug.WriteLine("FAILED to resolve service " + serviceType.Name);
  253.                 Debug.WriteLine("AT: " + Environment.StackTrace);
  254.                 Debug.WriteLine("******************************************");
  255.             }
  256.             #endif
  257.             Debug.Unindent();
  258.            
  259.             return service;
  260.         }
  261.        
  262.         /// <devdoc>
  263.         /// Removes the given service type from the service container.
  264.         /// </devdoc>
  265.         public void RemoveService(Type serviceType)
  266.         {
  267.             RemoveService(serviceType, false);
  268.         }
  269.        
  270.         /// <devdoc>
  271.         /// Removes the given service type from the service container.
  272.         /// </devdoc>
  273.         public virtual void RemoveService(Type serviceType, bool promote)
  274.         {
  275.             Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Removing service: " + serviceType.Name + ", Promote: " + promote.ToString());
  276.             if (promote) {
  277.                 IServiceContainer container = Container;
  278.                 if (container != null) {
  279.                     Debug.Indent();
  280.                     Debug.WriteLineIf(TRACESERVICE.TraceVerbose, "Invoking parent container");
  281.                     Debug.Unindent();
  282.                     container.RemoveService(serviceType, promote);
  283.                     return;
  284.                 }
  285.             }
  286.            
  287.             // We're going to remove this from our local list.
  288.             //
  289.             if (serviceType == null)
  290.                 throw new ArgumentNullException("serviceType");
  291.             Services.Remove(serviceType);
  292.         }
  293.     }
  294. }

Developer Fusion