下面我们继续分析剩下的三个Strategy:
1: stagedStrategyChain.AddNew<LocatorLookupStrategy>(BuilderStage.PreCreation);
2: stagedStrategyChain.AddNew<ConfiguredObjectStrategy>(BuilderStage.PreCreation);
3: stagedStrategyChain.AddNew<InstrumentationStrategy>(BuilderStage.PostInitialization);
先看LocatorLookupStrategy
1: public override void PreBuildUp(IBuilderContext context)
2: {
3: if (context.Locator != null)
4: {
5: Monitor.Enter(context.Locator);
6: context.RecoveryStack.Add(new LockReleaser(context.Locator));
7: object result = context.Locator.Get(context.BuildKey);
8: if (result != null)
9: {
10: context.Existing = result;
11: context.BuildComplete = true;
12: Monitor.Exit(context.Locator);
13: }
14: }
15: }
还记得我们在BuildUp中Locator是null,所以这个Strategy在这里没起任何作用
下面我们来看ConfiguredObjectStrategy,这个策略是整个装配过程的重点
1: /// <summary>2: /// Implementation of <see cref="IBuilderStrategy"/> which creates objects.3: /// </summary>4: /// <remarks>5: /// <para>The strategy looks for the <see cref="CustomFactoryAttribute">CustomFactory</see> attribute to6: /// retrieve the <see cref="ICustomFactory"/> implementation needed to build the requested types based on7: /// configuration.</para>8: /// <para>The provided context must have a <see cref="ConfigurationObjectPolicy"/> holding a <see cref="IConfigurationSource"/>9: /// where to request the configuration information.</para>10: /// </remarks>11: /// <seealso cref="ICustomFactory"/>12: /// <seealso cref="CustomFactoryAttribute"/>13: /// <seealso cref="ConfigurationObjectPolicy"/>
14: public class ConfiguredObjectStrategy : EnterpriseLibraryBuilderStrategy15: {
16: /// <summary>17: /// Override of <see cref="IBuilderStrategy.PreBuildUp"/>.18: /// Creates the requested object using the custom factory associated to the type specified by the context's key,19: /// and updates the context's existing object.20: /// </summary>21: /// <param name="context">The <see cref="IBuilderContext"/> that represents the current building process.</param>22: /// <exception cref="InvalidOperationException"> when the requested type does not have the23: /// required <see cref="CustomFactoryAttribute">CustomFactory</see> attribute.</exception>24: /// <exception cref="System.Configuration.ConfigurationErrorsException"> when the configuration for the requested ID is not present or is25: /// invalid in the configuration source.</exception>26: public override void PreBuildUp(IBuilderContext context)27: {
28: base.PreBuildUp(context);29:
30: IConfigurationSource configurationSource = GetConfigurationSource(context);
31: ConfigurationReflectionCache reflectionCache = GetReflectionCache(context);
32:
33: NamedTypeBuildKey key = (NamedTypeBuildKey) context.BuildKey;
34: string id = key.Name;35: Type t = key.Type;
36:
37: ICustomFactory factory = GetCustomFactory(t, reflectionCache);
38: if (factory != null)39: {
40: context.Existing = factory.CreateObject(context, id, configurationSource, reflectionCache);
41: }
42: else43: {
44: throw new InvalidOperationException(45: string.Format(46: Resources.Culture,
47: Resources.ExceptionCustomFactoryAttributeNotFound,
48: t.FullName,
49: id));
50: }
51: }
52:
53: private static ICustomFactory GetCustomFactory(Type t, ConfigurationReflectionCache reflectionCache)54: {
55: ICustomFactory customFactory = reflectionCache.GetCustomFactory(t);
56:
57: return customFactory;58: }
59: }
GetCustomFactory这句得到的是Database类中的Attribute标记的
[CustomFactory(typeof(DatabaseCustomFactory))]
string id是前一篇文章得到的DefaultDatabase或者是指定的数据连接字符串的Name
具体的追踪过程请参见该系列文章的第二篇
接下来我们来看DatabaseCustomFactory
1: /// <summary>2: /// This type supports the Enterprise Library infrastructure and is not intended to be used directly from your code.3: /// Represents the process to build a <see cref="Database"/> described by configuration information.4: /// </summary>5: public class DatabaseCustomFactory : ICustomFactory6: {
7: private IDictionary<Type, IDatabaseAssembler> assemblersMapping = new Dictionary<Type, IDatabaseAssembler>(5);8: private object assemblersMappingLock = new object();9:
10: /// <summary>11: /// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.12: /// Returns an <see cref="IDatabaseAssembler"/> that represents the building process for a a concrete <see cref="Database"/>.
13: /// </summary>14: /// <param name="type">The concrete <see cref="Database"/> type.</param>15: /// <param name="name">The name of the instance to build, or <see langword="null"/> (<b>Nothing</b> in Visual Basic).</param>16: /// <param name="reflectionCache">The cache to use retrieving reflection information.</param>17: /// <returns>The <see cref="IDatabaseAssembler"/> instance.</returns>18: /// <exception cref="InvalidOperationException">when concrete <see cref="Database"/> type does have the required <see cref="DatabaseAssemblerAttribute"/>.</exception>19: public IDatabaseAssembler GetAssembler(Type type, string name, ConfigurationReflectionCache reflectionCache)20: {
21: bool exists = false;22: IDatabaseAssembler assembler;
23: lock (assemblersMappingLock)24: {
25: exists = assemblersMapping.TryGetValue(type, out assembler);26: }
27: if (!exists)28: {
29: DatabaseAssemblerAttribute assemblerAttribute
30: = reflectionCache.GetCustomAttribute<DatabaseAssemblerAttribute>(type);
31: if (assemblerAttribute == null)32: throw new InvalidOperationException(33: string.Format(34: Resources.Culture,
35: Resources.ExceptionDatabaseTypeDoesNotHaveAssemblerAttribute,
36: type.FullName,
37: name));
38:
39: assembler
40: = (IDatabaseAssembler)Activator.CreateInstance(assemblerAttribute.AssemblerType);
41:
42: lock (assemblersMappingLock)43: {
44: assemblersMapping[type] = assembler;
45: }
46: }
47:
48: return assembler;49: }
50:
51: /// <summary>52: /// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.53: /// Returns a new instance of a concrete <see cref="Database"/>, described by the <see cref="ConnectionStringSettings"/>54: /// found in the <paramref name="configurationSource"/> under the name <paramref name="name"/>, plus any additional55: /// configuration information that might describe the the concrete <b>Database</b>.56: /// </summary>57: /// <param name="context">The <see cref="IBuilderContext"/> that represents the current building process.</param>58: /// <param name="name">The name of the instance to build, or <see langword="null"/> (<b>Nothing</b> in Visual Basic).</param>59: /// <param name="configurationSource">The source for configuration objects.</param>60: /// <param name="reflectionCache">The cache to use retrieving reflection information.</param>61: /// <returns>A new instance of the appropriate subtype of <typeparamref name="Tobject"/>.</returns>62: /// <exception cref="ConfigurationErrorsException">when the configuration is invalid or <paramref name="name"/> cannot be found.</exception>63: public object CreateObject(IBuilderContext context, string name, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)64: {
65: DatabaseConfigurationView configurationView = new DatabaseConfigurationView(configurationSource);66: ConnectionStringSettings connectionStringSettings = configurationView.GetConnectionStringSettings(name);
67: DbProviderMapping mapping = configurationView.GetProviderMapping(name, connectionStringSettings.ProviderName);
68:
69: IDatabaseAssembler assembler = GetAssembler(mapping.DatabaseType, name, reflectionCache);
70: Database database = assembler.Assemble(name, connectionStringSettings, configurationSource);
71:
72: return database;73: }
74: }
DatabaseConfigurationView就是把xxx.config当做只跟数据获取块有关的配置文件看待,这一点跟DataView有异曲同工之妙。
下面来看ConnectionStringSettings是怎么得到的。
1: /// <summary>2: /// Returns the <see cref="ConnectionStringSettings"/> object with the given name from the connection strings3: /// configuration section in the receiver's configuration source.4: /// </summary>5: /// <remarks>6: /// The connection string will be retrieved from the configuration source if it contains the connection strings section,7: /// otherwise it will be retrieved from the default configuration file.8: /// </remarks>9: /// <param name="name">The name for the desired connection string configuration.</param>10: /// <returns>The connection string configuration.</returns>11: /// <exception cref="ArgumentException">if <paramref name="name"/> is <see langword="null"/> (<b>Nothing</b> in Visual Basic) or empty.</exception>12: /// <exception cref="ConfigurationErrorsException">if the connection string object is not found, or if it does not specify a provider name.</exception>13: public ConnectionStringSettings GetConnectionStringSettings(string name)14: {
15: ValidateInstanceName(name);
16:
17: ConnectionStringSettings connectionStringSettings;
18: ConfigurationSection configSection = configurationSource.GetSection("connectionStrings");19: if ((configSection != null) && (configSection is ConnectionStringsSection))20: {
21: ConnectionStringsSection connectionStringsSection = configSection as ConnectionStringsSection;22: connectionStringSettings = connectionStringsSection.ConnectionStrings[name];
23: }
24: else25: connectionStringSettings = ConfigurationManager.ConnectionStrings[name];
26:
27: ValidateConnectionStringSettings(name, connectionStringSettings);
28: return connectionStringSettings;29: }
这里首先检索的是ConfigurationSource中是否含有connectionStrings配置节,如果不含有的话,再从默认的配置源(web.config或者app.config)中获取包含指定name的连接字符串
接下来我们看DbProviderMapping是怎么得到的
1: /// <summary>2: /// Returns the <see cref="DbProviderMapping"/> that specifies the mapping between an ADO.NET provider factory and a3: /// <see cref="Database"/> instance.4: /// </summary>5: /// <remarks>6: /// The mapping based in logical names will be probed first. If there is no success, the default type based mappings7: /// will be considered. If no default mapping is defined for the provider factory type, the generic database will be used.8: /// </remarks>9: /// <param name="name">The name of the <see cref="Database"/> instance.</param>10: /// <param name="dbProviderName">The logical provider name.</param>11: /// <returns>The <see cref="DbProviderMapping"/> that matches the <paramref name="dbProviderName"/>.</returns>12: public DbProviderMapping GetProviderMapping(string name, string dbProviderName)13: {
14: DatabaseSettings settings = this.DatabaseSettings;15: if (settings != null)16: {
17: DbProviderMapping existingMapping = settings.ProviderMappings.Get(dbProviderName);
18: if (existingMapping != null)19: {
20: return existingMapping;21: }
22: }
23:
24: DbProviderMapping defaultMapping = this.GetDefaultMapping(name, dbProviderName);25: if (defaultMapping != null)26: {
27: return defaultMapping;28: }
29:
30: return this.GetGenericMapping();31: }
说实在的,这段代码我很不理解,不理解的地方在于这句
DbProviderMapping existingMapping = settings.ProviderMappings.Get(dbProviderName);Settings的获得是从配置文件中的dataConfiguration配置节中读取的
然而ProviderMappings具有Attribute标记
[ConfigurationProperty(dbProviderMappingsProperty, IsRequired = false)]
其中dbProviderMappingsProperty=”providerMappings”
然而,无论我怎么在配置文件中找,也没有找到providerMappings这个配置节或者是属性
这样的话
[ConfigurationProperty(dbProviderMappingsProperty, IsRequired = false)]
public NamedElementCollection<DbProviderMapping> ProviderMappings
{
get
{
return (NamedElementCollection<DbProviderMapping>)base[dbProviderMappingsProperty];
}
}应该返回的是null?不知道ConfigurationManager.GetSection是怎么处理的,反正在MSDN上我是没有找到什么有用的资料,不知道有没有哪位不吝赐教。
如果那里返回的是null的话,这句话就该有空引用的异常
DbProviderMapping existingMapping = settings.ProviderMappings.Get(dbProviderName);如果不是null的话,又是如何实例化的NamedElementCollection<DbProviderMapping>呢
在此留下一个疑问,留待后人解决。
这里,我们可以猜测到,DbProviderMapping是用来根据配置文件中的ProviderName来确定的,从而根据这个mapping来获得相应的SqlDatabase或者是其他的Database。
IDatabaseAssembler assembler = GetAssembler(mapping.DatabaseType, name, reflectionCache);mapping.DatabaseType就是SqlDatabase或者OracleDatabase或者GenericDatabase,具体是哪个由配置文件决定。
/// <summary>
/// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
/// Returns an <see cref="IDatabaseAssembler"/> that represents the building process for a a concrete <see cref="Database"/>.
/// </summary>
/// <param name="type">The concrete <see cref="Database"/> type.</param>
/// <param name="name">The name of the instance to build, or <see langword="null"/> (<b>Nothing</b> in Visual Basic).</param>
/// <param name="reflectionCache">The cache to use retrieving reflection information.</param>
/// <returns>The <see cref="IDatabaseAssembler"/> instance.</returns>
/// <exception cref="InvalidOperationException">when concrete <see cref="Database"/> type does have the required <see cref="DatabaseAssemblerAttribute"/>.</exception>
public IDatabaseAssembler GetAssembler(Type type, string name, ConfigurationReflectionCache reflectionCache)
{
bool exists = false;
IDatabaseAssembler assembler;lock (assemblersMappingLock)
{
exists = assemblersMapping.TryGetValue(type, out assembler);
}
if (!exists)
{
DatabaseAssemblerAttribute assemblerAttribute
= reflectionCache.GetCustomAttribute<DatabaseAssemblerAttribute>(type);
if (assemblerAttribute == null)
throw new InvalidOperationException(
string.Format(
Resources.Culture,
Resources.ExceptionDatabaseTypeDoesNotHaveAssemblerAttribute,
type.FullName,
name));
assembler
= (IDatabaseAssembler)Activator.CreateInstance(assemblerAttribute.AssemblerType);
lock (assemblersMappingLock)
{
assemblersMapping[type] = assembler;
}
}
return assembler;
}这里通过反射得到了相应Database的程序集,比如说SqlDatabaseAssembler
然后通过该Assembler的Assemble方法得到了相应的Database
到这里,就已经完成了相应Database的创建。
下面是InstrumentationStrategy
1: public override void PreBuildUp(IBuilderContext context)2: {
3: base.PreBuildUp(context);4:
5: if (context.Existing != null && context.Existing is IInstrumentationEventProvider)6: {
7: IConfigurationSource configurationSource = GetConfigurationSource(context);
8: ConfigurationReflectionCache reflectionCache = GetReflectionCache(context);
9:
10: NamedTypeBuildKey key = (NamedTypeBuildKey)context.BuildKey;
11: string id = key.Name;12:
13: InstrumentationAttachmentStrategy instrumentation = new InstrumentationAttachmentStrategy();14:
15: if (ConfigurationNameProvider.IsMadeUpName(id))16: {
17: instrumentation.AttachInstrumentation(context.Existing, configurationSource, reflectionCache);
18: }
19: else20: {
21: instrumentation.AttachInstrumentation(id, context.Existing, configurationSource, reflectionCache);
22: }
23: }
24: }
检查了所有的Database,发现其父类Database实现了IInstrumentationEventProvider接口。
我们来看ConfigurationNameProvider的IsMadeUpName方法
1: /// <summary>2: /// Manages the creation of names for anonymous instances.3: /// </summary>4: public static class ConfigurationNameProvider5: {
6: private const string nameSuffix = "___";7:
8: /// <summary>9: /// Creates a new name.10: /// </summary>11: /// <returns>The created name.</returns>12: public static string MakeUpName()13: {
14: return Guid.NewGuid().ToString() + nameSuffix;15: }
16:
17: /// <summary>18: /// Tests a name to determine if it has been created.19: /// </summary>20: /// <param name="name">The name to test.</param>21: /// <returns><b>true</b> if the name was made up.</returns>22: public static bool IsMadeUpName(string name)23: {
24: if (name == null) return false;25:
26: return name.EndsWith(nameSuffix);27: }
28: }
根据注释,ConfigurationNameProvider就是专门用来管理BuildKey.Name的类。这个类的MakeUpName方法在前面的分析中没有被调用过,而且BuildKey.Name也不是以"___"结尾,所以应该进入方法:
instrumentation.AttachInstrumentation(id, context.Existing, configurationSource, reflectionCache);/// <summary>
/// Drives binding of instrumentation events to handler methods based on the attributes on the
/// source object.
/// </summary>
public class InstrumentationAttachmentStrategy
{
InstrumentationAttacherFactory attacherFactory = new InstrumentationAttacherFactory();
/// <overloads>
/// Attaches the instrumentation events in the <paramref name="createdObject"></paramref> to the
/// creating instance of the listener object, as defined by the <see cref="InstrumentationListenerAttribute"></see>
/// on the source class.
/// </overloads>
/// <summary>
/// Attaches the instrumentation events in the <paramref name="createdObject"></paramref> to the
/// creating instance of the listener object, as defined by the <see cref="InstrumentationListenerAttribute"></see>
/// on the source class.
/// </summary>
/// <param name="createdObject">Source object used for instrumentation events.</param>
/// <param name="configurationSource"><see cref="IConfigurationSource"></see> instance used to define whether
/// instrumentation is enabled or disabled for application.</param>
/// <param name="reflectionCache">Cache for instrumentation attributes discovered through reflection.</param>
public void AttachInstrumentation(object createdObject, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
{
ArgumentGenerator arguments = new ArgumentGenerator();
AttachInstrumentation(arguments, createdObject, configurationSource, reflectionCache);
}
/// <summary>
/// Attaches the instrumentation events in the <paramref name="createdObject"></paramref> to the
/// creating instance of the listener object, as defined by the <see cref="InstrumentationListenerAttribute"></see>
/// on the source class.
/// </summary>
/// <param name="instanceName">User-provided instance name given to the instrumenation listener during its instantiation.</param>
/// <param name="createdObject">Source object used for instrumentation events.</param>
/// <param name="configurationSource"><see cref="IConfigurationSource"></see> instance used to define whether
/// instrumentation is enabled or disabled for application.</param>
/// <param name="reflectionCache">Cache for instrumentation attributes discovered through reflection.</param>
public void AttachInstrumentation(string instanceName, object createdObject, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
{
ArgumentGenerator arguments = new ArgumentGenerator(instanceName);
AttachInstrumentation(arguments, createdObject, configurationSource, reflectionCache);
}
private void AttachInstrumentation(ArgumentGenerator arguments, object createdObject,
IConfigurationSource configurationSource,
ConfigurationReflectionCache reflectionCache)
{
InstrumentationConfigurationSection section = GetConfigurationSection(configurationSource);
if (section.InstrumentationIsEntirelyDisabled) return;
if (createdObject is IInstrumentationEventProvider)
{
createdObject = ((IInstrumentationEventProvider)createdObject).GetInstrumentationEventProvider();
}
object[] constructorArgs = arguments.ToArguments(section);
BindInstrumentationTo(createdObject, constructorArgs, reflectionCache);
}
private void BindInstrumentationTo(object createdObject, object[] constructorArgs, ConfigurationReflectionCache reflectionCache)
{
IInstrumentationAttacher attacher = attacherFactory.CreateBinder(createdObject, constructorArgs, reflectionCache);
attacher.BindInstrumentation();
}
private InstrumentationConfigurationSection GetConfigurationSection(IConfigurationSource configurationSource)
{
InstrumentationConfigurationSection section =
(InstrumentationConfigurationSection)configurationSource.GetSection(InstrumentationConfigurationSection.SectionName);
if (section == null) section = new InstrumentationConfigurationSection(false, false, false);
return section;
}
private class ArgumentGenerator
{
private string instanceName;
public ArgumentGenerator(string instanceName)
{
this.instanceName = instanceName;
}
public ArgumentGenerator() { }
public object[] ToArguments(InstrumentationConfigurationSection configSection)
{
return instanceName == null
?
new object[] { configSection.PerformanceCountersEnabled, configSection.EventLoggingEnabled, configSection.WmiEnabled, configSection.ApplicationInstanceName }
:
new object[]
{
instanceName, configSection.PerformanceCountersEnabled, configSection.EventLoggingEnabled,
configSection.WmiEnabled, configSection.ApplicationInstanceName
};
}
}
}首先,AttachInstrumentation方法构造了一个用来传递参数的类ArgumentGenerator。然后通过configurationSource获得了InstrumentationConfigurationSection配置节,如果该配置节不存在,就创建一个PerformanceCountersEnabled,EventLoggingEnabled,WmiEnabled都为False的InstrumentationConfigurationSection实例。
紧接着,在这句,如果没有配置过InstrumentationConfigurationSection的话
if (section.InstrumentationIsEntirelyDisabled) return;就返回了,因为
internal bool InstrumentationIsEntirelyDisabled
{
get { return (PerformanceCountersEnabled || EventLoggingEnabled || WmiEnabled) == false; }
}而刚刚直接新建了一个这三个值都是False的InstrumentationConfigurationSection实例。
如果配置过InstrumentationConfigurationSection的话,createObject是某个Database的实例,他们都继承自Database类,Database类实现了接口IInstrumentationEventProvider,该方法返回了类DataInstrumentationProvider。现在createObject指向了Database返回的类DataInstrumentationProvider。接下来,刚刚构造的用来生成参数的类ArgumentGenerator生成了一系列参数。
接下来我们来看那个attacher。
IInstrumentationAttacher attacher = attacherFactory.CreateBinder(createdObject, constructorArgs, reflectionCache);首先得看attacherFactory。attacherFactory是在类InstrumentationAttachmentStrategy一开始就声明并赋值的一个变量。
InstrumentationAttacherFactory attacherFactory = new InstrumentationAttacherFactory();
我们来看InstrumentationAttacherFactory的CreateBinder方法
1: /// <summary>2: /// Represents a factor to attach instrumentation objects.3: /// </summary>4: public class InstrumentationAttacherFactory5: {
6: /// <summary>7: /// Create the binder for instrumentation.8: /// </summary>9: /// <param name="createdObject">The created object for the attacher.</param>10: /// <param name="constructorArgs">The construcor objects.</param>11: /// <param name="reflectionCache">The relection cache.</param>12: /// <returns>An <see cref="IInstrumentationAttacher"/> object.</returns>13: public IInstrumentationAttacher CreateBinder(object createdObject,14: object[] constructorArgs,15: ConfigurationReflectionCache reflectionCache)
16: {
17: InstrumentationListenerAttribute listenerAttribute = GetInstrumentationListenerAttribute(createdObject, reflectionCache);
18:
19: if (listenerAttribute == null) return new NoBindingInstrumentationAttacher();20:
21: Type listenerType = listenerAttribute.ListenerType;
22: Type listenerBinderType = listenerAttribute.ListenerBinderType;
23:
24: if (listenerBinderType == null) return new ReflectionInstrumentationAttacher(createdObject, listenerType, constructorArgs);25: return new ExplicitInstrumentationAttacher(createdObject, listenerType, constructorArgs, listenerBinderType);26: }
27:
28: static InstrumentationListenerAttribute GetInstrumentationListenerAttribute(object createdObject,29: ConfigurationReflectionCache reflectionCache)
30: {
31: Type createdObjectType = createdObject.GetType();
32: InstrumentationListenerAttribute listenerAttribute
33: = reflectionCache.GetCustomAttribute<InstrumentationListenerAttribute>(createdObjectType, true);34: return listenerAttribute;35: }
36: }
首先,用ConfigurationReflectionCache反射得到了createObject的InstrumentationListenerAttribute,也就是DataInstrumentationProvider的InstrumentationListenerAttribute:
[InstrumentationListener(typeof(DataInstrumentationListener), typeof(DataInstrumentationListenerBinder))]
public class DataInstrumentationProvider然后返回了一个ExplicitInstrumentationAttacher,我们来看ExplicitInstrumentationAttacher的BindInstrumentation方法
1: public void BindInstrumentation()2: {
3: IExplicitInstrumentationBinder binder = (IExplicitInstrumentationBinder) Activator.CreateInstance(explicitBinderType);
4: object listener = Activator.CreateInstance(listenerType, listenerConstructorArguments);5:
6: binder.Bind(source, listener);
7: }
先创建了刚刚得到的InstrumentationListenerAttribute中的DataInstrumentationListenerBinder。然后用刚刚的参数生成类ArgumentGenerator生成的参数创建了DataInstrumentationListener。然后调用Binder的Bind方法将DataInstrumentationListener和DataInstrumentationProvider绑定到一起。
这样一来,每当出现指定的操作的时候,就可以根据配置文件中的配置来决定是否进行性能计数,事件日志等操作。具体来说,就是将DataInstrumentationProvider中的事件
1: /// <summary>2: /// Occurs when a new database connection is opened by a <see cref="Database"/> instance.3: /// </summary>4: [InstrumentationProvider("ConnectionOpened")]5: public event EventHandler<EventArgs> connectionOpened;6:
7: /// <summary>8: /// Occurs when the attempt to open a new database connection by a <see cref="Database"/> instance fails.9: /// </summary>10: [InstrumentationProvider("ConnectionFailed")]11: public event EventHandler<ConnectionFailedEventArgs> connectionFailed;12:
13: /// <summary>
14: /// Occurs when a database command is executed by a <see cref="Database"/> instance.15: /// </summary>16: [InstrumentationProvider("CommandExecuted")]17: public event EventHandler<CommandExecutedEventArgs> commandExecuted;18:
19: /// <summary>20: /// Occurs when the attempt to execute a database command by a <see cref="Database"/> instance fails.21: /// </summary>22: [InstrumentationProvider("CommandFailed")]23: public event EventHandler<CommandFailedEventArgs> commandFailed;绑定到具体处理这些事件的类DataInstrumentationListener上
1: public void Bind(object source, object listener)2: {
3: DataInstrumentationListener castedListener = (DataInstrumentationListener)listener;
4: DataInstrumentationProvider castedProvider = (DataInstrumentationProvider)source;
5:
6: castedProvider.commandExecuted += castedListener.CommandExecuted;
7: castedProvider.commandFailed += castedListener.CommandFailed;
8: castedProvider.connectionFailed += castedListener.ConnectionFailed;
9: castedProvider.connectionOpened += castedListener.ConnectionOpened;
10: }
至此,所有的Strategy都分析完毕。
DatabaseFactory的工作原理也就明晰了。