为Enterprise Library 5.0 添加自定义程序块

概述

        最近研究 Enterprise Library 5.0 发现确实是个好东西,于是尝试看能否将其运用的自己的项目中。通过网上资料零零碎碎的资料,以及自己阅读源代码,发现如果要在EnterLib中加入自己的程序块的话需要进行以下步骤“

        1)定制自己的配置类,这个类用于保存自定义程序快的配置信息,他需要继承 SerializableConfigurationSection类同时实现 ITypeRegistrationsProvider接口。 SerializableConfigurationSection是一个可序列化的配置区域,ITypeRegistrationsProvider 是为EnterLib的DI提供类型注册的接口,也就是EnterLib的配置管理需要知道我们要怎样创建对象,自定义程序块就是通过实现ITypeRegistrationsProvider 接口来告诉EnterLib配置管理模块的。

       2)在配置区域加入 typeRegistrationProvidersConfiguration 区域(我理解为类型注册提供者配置区域,不知道对不对,姑且先这样理解吧。)

 <section name="typeRegistrationProvidersConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.TypeRegistrationProvidersConfigurationSection,Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral"/>

        之所以加入这个区域通过阅读源代码发现EnterLib在初始化配置时候先要检查是否有 typeRegistrationProvidersConfiguration 配置区(类型提供者),如果没有那么就加载默认的类型集合。那么我们完全可以通过这个加入自定义程序块的配置区了。EnterLib的默认程序块 是在TypeRegistrationProviderElementCollection 类的构造函数中添加的,他添加了EnterLib本身提供的各种程序块,如日志 、安全、验证、加密、数据访问等等。

          通过以上两步就可以通过EnterLib来创建自定义程序块了。下面以一个简单的例子说明从代码层面怎么去实现。

实例

          最近为公司做了一个数字展厅的中控系统,其中需要使用IPAD来控制展厅内部的所有硬件,包括投影机开关、灯光开关、窗帘开关、PC终端上的各种播控软件。从设计的角度出发这个系统包含以下对象:

       1) 指令实体:用于存储指令内容,指令类型,目标终端等信息。

       2) 终端实体:用于存储终端设备的各种属性信息。

       3) 指令解析器:用于解析并执行指令内容。

       4) 指令上下文提供者:也可以理解为指令数据源提供者,他可以是数据库,也可以是XML文件,也可以是文本文件。

       上面这些内容视乎与本文的主题没有太大关系,不过要灵活并且正确的应用一些技术,一些实例是需求背景,以及设计思路有一定的了解还是有必要的。下面转会正题,看看本实例是如何进行与EnterLib结合在一起,开发自己的程序块的吧。

       首先本实例有两个是可能会发生变动以及以后可能会扩展的,一个是整个系统的信息源来可能来自于各种不同版本的数据库,文本文件,XML文件都有可能。另一个是面对各种不同的终端需要不同的指令解析器,对指令内容进行解析和执行。这两个可能变动的地方,都让他通过EnterLib变得可配置。让程序运行时去决定使用那个数据源,以及指令类型与指令解析器的对应关系。类图如下:

        

            上图中类和接口的用途如下:

            BaseCMDSettings: 用于保存整个系统的配置,EnterLib通过读取配置信息从而知道如何创建类的实例。它需要继承 SerializableConfigurationSection 类和实现 ITypeRegistrationsProvider接口。

            ContextProviderData:指令实体内容提供者配置数据(也就是数据源提供者),通过他来保存系统使用的是那一个数据源。他需要继承NameTypeConfigurationElement 最好还在这个类里面加入一个 IEnumerable<TypeRegistration> GetRegistrations() 方法用于返回 类型注册信息。

            ResolverData:指令解析器配置数据。用于配置那种指令使用那一个指令解析器。

            ResolverCollection:指令解析器集合,用于保存整个系统中所有指令类型与指令解析器的对应关系,需要继承 PolymorphicConfigurationElementCollection<ResolverData>并且重写

override Type RetrieveConfigurationElementType(System.Xml.XmlReader reader)方法.

           IBaseCMDContextProvider:指令内容提供者接口

           IBaseCMDResolver:指令解析器接口

          基本上就是上面这些类了,下面先看看怎么配置吧,如下代码:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <!--类型提供者 配置区 start-->
    <section name="typeRegistrationProvidersConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Common.Configuration.TypeRegistrationProvidersConfigurationSection,Microsoft.Practices.EnterpriseLibrary.Common, Version=5.0.414.0, Culture=neutral"/>
    <!--类型提供者 配置区 end-->
    <section name="baseCmdSettings" type=" QuickStart.Configuration.BaseCMDSettings,QuickStart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" requirePermission="true"/>
  </configSections>
  <!--类型提供者 配置区 start-->
  <typeRegistrationProvidersConfiguration>

    <!-- 可以加入EnterLib 自身的程序块-->
    <!--加入中控配置-->
    <add sectionName="baseCmdSettings" providerType="" name="baseCmdSettings" />
  </typeRegistrationProvidersConfiguration>
  <!--类型提供者 配置区 end-->
  <!--中控配置区 配置区 start-->
  <baseCmdSettings configSource="ConfigFiles\baseCmdSettings.config"/>
  <!--中控配置区 配置区 end-->
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>

        本实例中我们将 中控配置加入到 另一个配置文件中 ConfigFiles\baseCmdSettings.config中。该配置文件内容如下:

<?xml version="1.0" encoding="utf-8" ?>
<baseCmdSettings name="">

<!-- 指令实体提供者 配置本例中使用 MySqlBaseCMDContextProvider来作为  IBaseCMDContextProvider 内容提供接口的 实现类,当然还可以是其他类-->
<contextProvider name="ContextProvider" type="QuickStart.MySqlBaseCMDContextProvider, QuickStart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
    <resolvers>
        <clear />

           <!-添加了两个指令解析器 一来实现分别作为 PC指令(name=PcCmd),以及中控主机指令(name=CCCmd)的实现类 EnterLib会根据提供的name来创建 IBaseCMDResolver

指令解析接口的实现类-->
        <add type="QuickStart.PCBaseCMDResovler, QuickStart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="PcCmd" />
        <add type="QuickStart.CCBaseCMDResovler, QuickStart, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="CCCmd" />
    </resolvers>
</baseCmdSettings>

BaseCMDSettings的代码如下:

public class BaseCMDSettings : SerializableConfigurationSection, ITypeRegistrationsProvider
    {
        public const string SectionName = "baseCmdSettings";
        private const string resolverProperty = "resolvers";
        private const string providerProperty = "contextProvider";
        private const string nameProperty = "name";

        /// <summary>
        /// 构造函数
        /// </summary>
        public BaseCMDSettings()
        {
            this.ContextProvider = new ContextProviderData() { Name = "ContextProvider", Type = typeof(MySqlBaseCMDContextProvider) };
            this.BaseCMDResolvers = new ResolverCollection();
            this.BaseCMDResolvers.Add(new ResolverData() { Name = "PcCmd", Type = typeof(PCBaseCMDResovler) });
            this.BaseCMDResolvers.Add(new ResolverData() { Name = "CCCmd", Type = typeof(CCBaseCMDResovler) });
        }
        /// <summary>
        /// 指令上下文提供者
        /// </summary>
        [ConfigurationProperty(providerProperty, IsRequired = true)]
        public ContextProviderData ContextProvider
        {
            get
            {
                return (ContextProviderData)base[providerProperty];
            }
            set
            {
                this[providerProperty] = value;
            }
        }
        [ConfigurationProperty(nameProperty, IsRequired = true, DefaultValue = "The Multimedia Exhibition Hall System Settings of Wise Union ")]
        public string Name
        {
            get
            {
                return (String)this[nameProperty];
            }
            set
            {
                this[nameProperty] = value;
            }
        }
        /// <summary>
        /// 指令解析器集合
        /// </summary>

        [ConfigurationProperty(resolverProperty, IsRequired = true)]
        public ResolverCollection BaseCMDResolvers
        {
            get
            {
                return (ResolverCollection)base[resolverProperty];
            }
            set
            {
                this[resolverProperty] = value;
            }
        }

        /// <summary>
        /// 创建类型注册
        /// </summary>
        /// <param name="configurationSource"></param>
        /// <returns></returns>
        private IEnumerable<TypeRegistration> GetRegistrationsCore(IConfigurationSource configurationSource)
        {
            var registrations = new List<TypeRegistration>();
            registrations.AddRange(this.ContextProvider.GetRegistrations());
           
            registrations.AddRange(this.BaseCMDResolvers.SelectMany(rl => rl.GetRegistrations()));
            return registrations;
        }
   
       
       
        #region ITypeRegistrationsProvider 接口成员
        /// <summary>
        /// 获取注册类型集合
        /// </summary>
        /// <param name="configurationSource"></param>
        /// <returns></returns>
        public IEnumerable<TypeRegistration> GetRegistrations(IConfigurationSource configurationSource)
        {
            return this.GetRegistrationsCore(configurationSource);
        }
        /// <summary>
        /// 更新注册类型
        /// </summary>
        /// <param name="configurationSource"></param>
        /// <returns></returns>
        public IEnumerable<TypeRegistration> GetUpdatedRegistrations(IConfigurationSource configurationSource)
        {
            return this.GetRegistrationsCore(configurationSource);
        }
        #endregion
    }


ContextProviderData的代码如下:

 public class ContextProviderData : NameTypeConfigurationElement
    {
        public virtual IEnumerable<TypeRegistration> GetRegistrations()
        {
            yield return new TypeRegistration(
                 RegistrationExpressionBuilder.BuildExpression(this.Type, null), typeof(IBaseCMDContextProvider))
                 {
                     Lifetime = TypeRegistrationLifetime.Singleton,
                     IsDefault = true
                 };
        }
    }

ResolverCollection代码如下:


  /// <summary>
    /// 指令解析者集合
    /// </summary>
    public class ResolverCollection : PolymorphicConfigurationElementCollection<ResolverData>
    {
        public const string typeName = "type";
        protected override Type RetrieveConfigurationElementType(System.Xml.XmlReader reader)
        {
            Type configurationElementType = typeof(ResolverData);
            return configurationElementType;          
        }
    }

ResolverData 代码如下:

  public class ResolverData : NameTypeConfigurationElement
    {
        public virtual IEnumerable<TypeRegistration> GetRegistrations()
        {
            yield return new TypeRegistration(
                RegistrationExpressionBuilder.BuildExpression(this.Type, null), typeof(IBaseCMDResolver))
            {
                Lifetime = TypeRegistrationLifetime.Singleton,
                IsDefault = true,
                Name = this.Name
            };
        }
    }

其他具体实现类的代码如下:

    public class CCBaseCMDResovler:BaseCMDResolver
    {
        public CCBaseCMDResovler(NameValueCollection parameters)
        {
        }
        public override void Execute()
        {
            Console.WriteLine("This is CCBaseCMDResovler Execute");
        }
    }
    public class PCBaseCMDResovler : BaseCMDResolver
    {
        public PCBaseCMDResovler(NameValueCollection parameters)
        {
        }
        public override void Execute()
        {
            Console.WriteLine("This is PCBaseCMDResovler Execute");
        }
    }


  public abstract class BaseCMDResolver:IBaseCMDResolver
    {
        public abstract void Execute();       
    }


/// </summary>
    public class MySqlBaseCMDContextProvider:IBaseCMDContextProvider
    {
        public MySqlBaseCMDContextProvider(NameValueCollection parameters)
        {
        }
        public IList<BaseCMDEntity> GetBaseCMDEntitys()
        {
            return new List<BaseCMDEntity>();
        }

        public IList<BaseCMDEntity> GetBaseCMDEntitys(params string[] types)
        {
            return new List<BaseCMDEntity>();
        }

        public IList<BaseCMDEntity> GetBaseCMDEntitysByGroupID(string groupid)
        {
            return new List<BaseCMDEntity>();
        }

        public BaseCMDEntity GetBaseCMDEntity(string id)
        {
            return new BaseCMDEntity();
        }


        public void Write()
        {
            Console.WriteLine("This Is MySqlBaseCMDContextProvider Write");
        }
    }


          到此所有代码都结束了,下面我们来看看运行结果吧

         IBaseCMDContextProvider provider = EnterpriseLibraryContainer.Current.GetInstance<IBaseCMDContextProvider>();
            provider.Write();

            IBaseCMDResolver resolver = EnterpriseLibraryContainer.Current.GetInstance<IBaseCMDResolver>("PcCmd");
            resolver.Execute();


            resolver = EnterpriseLibraryContainer.Current.GetInstance<IBaseCMDResolver>("CCCmd");
            resolver.Execute();

         执行以上代码会输出:

This Is MySqlBaseCMDContextProvider Write
This is PCBaseCMDResovler Execute
This is CCBaseCMDResovler Execute

小结:

              以上方法是简单的实现了向EnterLib容器中注册新的程序块,然而不知道是不是最佳方式,因此此文只做个人学习所用。有不对的,还忘多多指正。


    


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值