1: using System;
2: using System.Collections;
3: using System.Reflection;
4: using System.Text;
5: using Microsoft.Practices.EnterpriseLibrary.Configuration;
6: using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
7:
8: namespace XXX.Toolbox.Services
9: { 10: /// <summary>
11: /// The service factory allows callers to instantiate any configured service.
12: /// </summary>
13: /// <remarks>
14: /// This class utilises the Enterprise Library for both its configuration and
15: /// exception handling and the following is therefore a prerequisite.
16: /// Configuration Application Block Configuration Section named "ServiceFactory",
17: /// using Serializer Transformer and XML File Storage Provider, pointing to the
18: /// servicefactory.config file.ServiceFactory.config must be configured to define
19: /// all services to be hosted by the service factory. Running the ServiceFactoryTest
20: /// console application with the /i runtime option will create an example file.
21: /// Exception Application Block Exception Policy named "Service Factory Policy".
22: /// Firstly ensure that an Exception type is defined as part of the above policy,
23: /// with a logging handler and a wrap handler, as well as a "NotifyRethrow" action.
24: /// The wrap handler must specify the ServiceFactoryException as defined in
25: /// ServiceFactory.dll. Secondly define a ServiceFactoryException type, with a
26: /// logging handler and a "NotifyRethrow" action.
27: /// See App.config and ServiceFactory.config files shipped with
28: /// the ServiceFactoryTest console application for more details.
29: /// </remarks>
30: public sealed class ServiceFactory : ProviderFactory, IDisposable
31: { 32: #region Constructors
33: /// <summary>
34: /// Service factory constructor
35: /// Calls second constructor with current configuration context
36: /// </summary>
37: private ServiceFactory() : this(ConfigurationManager.GetCurrentContext())
38: { 39: }
40:
41: /// <summary>
42: /// Calls base constructor of FactoryProvider with specified configuration context
43: /// </summary>
44: /// <param name="context"></param>
45: private ServiceFactory(ConfigurationContext context) : base("Service Factory", context, typeof(FactoryConfigProvider)) 46: { 47: }
48:
49: /// <summary>
50: /// Destructor
51: /// </summary>
52: ~ServiceFactory()
53: { 54: Dispose(false);
55: }
56: #endregion
57:
58: #region IDisposable Members
59: /// <summary>
60: /// Dispose method, which releases all resources used by the object.
61: /// </summary>
62: public void Dispose()
63: { 64: this.Dispose ( true );
65: }
66:
67: /// <summary>
68: /// Releases the unmanaged resources used by the object and optionally releases the managed resources
69: /// </summary>
70: /// <param name="disposing">Indicator whether called by destructor (false) or custom (true).</param>
71: public void Dispose ( bool disposing )
72: { 73: if ( disposing ) GC.SuppressFinalize(this);
74:
75: // Cull Cache Items
76: IDictionaryEnumerator myEnumerator = singletonHashTable.GetEnumerator();
77: while ( myEnumerator.MoveNext() )
78: { 79: IDisposable serviceInstance = myEnumerator.Value as IDisposable;
80: if ( null != serviceInstance ) serviceInstance.Dispose();
81: }
82:
83: // Cull Cache
84: singletonHashTable.Clear();
85: }
86: #endregion
87:
88: #region Instance
89: /// <summary>
90: /// Service Factory Instance Property
91: /// </summary>
92: public static ServiceFactory Instance
93: { 94: get
95: { 96: if ( null == instance )
97: { 98: lock ( synchRoot )
99: { 100: if ( null == instance )
101: instance = new ServiceFactory();
102: }
103: }
104: return ( instance);
105: }
106: }
107: #endregion
108:
109: #region Methods
110: /// <summary>
111: /// Locator method, which determines if service is in the known configuration and if yes, whether
112: /// it has already been loaded as a singelton.
113: /// </summary>
114: /// <param name="name">Name of service</param>
115: /// <param name="serviceConfig">Service configuration if found</param>
116: /// <param name="serviceReference">Service reference if loaded as a singleton</param>
117: private void LocateService ( string name, out FactoryServiceConfig serviceConfig, out object serviceReference )
118: { 119: bool bFound = false;
120: serviceConfig = null;
121: serviceReference = null;
122:
123: providerData = (FactoryConfigProvider)this.CreateInstance(FactoryConfig.SectionName);
124:
125: // We scan the configuration first, because the singelton state may have changed in the interim
126: foreach (FactoryServiceConfig service in providerData.GetFactoryConfig().FactoryServiceConfig)
127: { 128: if ( 0 == service.Name.ToLower(System.Globalization.CultureInfo.CurrentCulture).CompareTo(name.ToLower(System.Globalization.CultureInfo.CurrentCulture)) )
129: { 130: serviceConfig = service;
131: bFound = true;
132: break;
133: }
134: }
135:
136: // Scan the cache if we are OK
137: if ( ( true == bFound ) && ( true == serviceConfig.Singleton ) )
138: { 139: if ( true == singletonHashTable.ContainsKey(name) )
140: { 141: serviceReference = singletonHashTable[name];
142: }
143: }
144: else
145: if ( false == bFound )
146: { 147: throw ServiceFactoryException.Create ( ExceptionCategory.ServiceNotFound, name, null );
148: }
149: }
150:
151: /// <summary>
152: /// Helper method to format the public key and public key token in hexadecimal format
153: /// </summary>
154: /// <param name="assembly">Assembly from which keys are to be extracted</param>
155: /// <param name="publicKey">Hexadecimal display of public key</param>
156: /// <param name="publicKeyToken">Hexadecimal display of public key token</param>
157: private static void GetKeyInformation ( Assembly assembly, out string publicKey, out string publicKeyToken )
158: { 159: StringBuilder key = new StringBuilder();
160: StringBuilder token = new StringBuilder();
161:
162: publicKey = null;
163: publicKeyToken = null;
164:
165: byte[] publicKeyBytes = assembly.GetName().GetPublicKey();
166: if ( null != publicKeyBytes )
167: { 168: for ( int i=0; i < publicKeyBytes.GetLength(0); i++ ) key.AppendFormat( "{0:x2}", publicKeyBytes
); 169: publicKey = key.ToString();
170: }
171:
172: byte[] publicKeyTokenBytes = assembly.GetName().GetPublicKeyToken();
173: if ( null != publicKeyTokenBytes )
174: { 175: for (int i=0; i < publicKeyTokenBytes.GetLength(0); i++) token.AppendFormat( "{0:x2}", publicKeyTokenBytes
); 176: publicKeyToken = token.ToString();
177: }
178: }
179: