概述
最近研究 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容器中注册新的程序块,然而不知道是不是最佳方式,因此此文只做个人学习所用。有不对的,还忘多多指正。