下面我们继续分析剩下的三个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 to 6: /// retrieve the <see cref="ICustomFactory"/> implementation needed to build the requested types based on 7: /// 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 : EnterpriseLibraryBuilderStrategy 15: { 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 the 23: /// 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 is 25: /// 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: else 43: { 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 : ICustomFactory 6: { 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 additional 55: /// 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 strings 3: /// 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: else 25: 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 a 3: /// <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 mappings 7: /// 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: else 20: { 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 ConfigurationNameProvider 5: { 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 InstrumentationAttacherFactory 5: { 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的工作原理也就明晰了。
转载于:https://www.cnblogs.com/HCOONa/archive/2009/07/15/1524402.html
相关资源:微软企业库6.0源码