Adhesive框架系列文章--配置服务模块使用

上一篇文章中提到配置服务模块分为服务端和客户端,作为使用者只需要关心客户端的一些接口就行了。我们来看一下这些接口的定义。

public interface IConfigService
    {
        T GetConfigItemValue<T>(string cateName, T defVal);
        T GetConfigItemValue<T>(string cateName, T defVal, ConfigItemValueUpdateCallback callback);
        T GetConfigItemValue<T>(string cateName, string itemName, T defVal);
        T GetConfigItemValue<T>(string cateName, string itemName, T defVal, ConfigItemValueUpdateCallback callback);
        T GetConfigItemValue<T>(string cateName, string subcateName, string itemName, T defVal);
        T GetConfigItemValue<T>(string cateName, string subcateName, string itemName, T defVal, ConfigItemValueUpdateCallback callback);
        T GetConfigItemValue<T>(string[] pathItemNames, T defVal);
        T GetConfigItemValue<T>(string[] pathItemNames, T defVal, ConfigItemValueUpdateCallback callback);
        T GetConfigItemValue<T>(bool global, string cateName, T defVal);
        T GetConfigItemValue<T>(bool global, string cateName, T defVal, ConfigItemValueUpdateCallback callback);
        T GetConfigItemValue<T>(bool global, string cateName, string itemName, T defVal);
        T GetConfigItemValue<T>(bool global, string cateName, string itemName, T defVal, ConfigItemValueUpdateCallback callback);
        T GetConfigItemValue<T>(bool global, string cateName, string subcateName, string itemName, T defVal);
        T GetConfigItemValue<T>(bool global, string cateName, string subcateName, string itemName, T defVal, ConfigItemValueUpdateCallback callback);
        T GetConfigItemValue<T>(bool global, string[] pathItemNames, T defVal);
        T GetConfigItemValue<T>(bool global, string[] pathItemNames, T defVal, ConfigItemValueUpdateCallback callback);
    }

虽然以上重载的方法比较多,但可以分为两类,一类是不带global参数的(默认为true),一类是带global参数的。global参数表示该配置是否是全局配置。配置根据应用范围分为两类,一种是全局配置,另一种是私有配置,只在自己的应用程序范围内使用,归属于自己的应用程序名称下。这样划分的好处有两点,第一,有的时候,同样的一个配置,由于应用的不同,具体的设置也会存在差异;第二,减少了配置同步时的数据量,同步时只需要关心全局配置和自己应用程序的配置。配置是有层级的,比如说某个业务下某个模块下的某个配置,可以通过cateName参数指定位于第一层级配置节点的名称,通过subcateName参数指定位于第二层级配置节点的名称,通过itemName参数指定位于第三层级配置节点的名称。配置模块支持无限层级,如果要访问三层以上的配置节点可以使用带有pathItemNames参数的重载方法,指定要访问配置节点的路径即可。每个方法都有一个泛型参数T,该参数代表配置的数据类型,配置模块支持的数据类型见下表:

image

 

defVal参数表示配置节点的默认值,获取配置时,如果该配置节点的值为空(没有配置),可以通过指定该参数返回一个默认值。如果配置节点不存在,则会自动创建,并且会根据指定的默认值初始化配置节点的值。callback参数表示当配置更新时,需要回调的方法名称,可以在回调方法中再次获取更新后的配置,这是一种被动模式。另外还有一种主动模式是每次都去获取,配置更新后也可以获取到最新的配置。

下面举一些调用的例子:

1、基础数据类型配置

1.1、获取全局的路径为TradingConfig--SearchConfig--EnableNewEditionSearch的配置(不带回调):

_enableNewEditionSearch = _configService.GetConfigItemValue("TradingConfig", "SearchConfig", "EnableNewEditionSearch", false);
  Console.WriteLine(_enableNewEditionSearch);

输出结果:

image

 

Web后台:

image

 

将EnableNewEditionSearch节点的值修改为True:

image

客户端输出结果:

image

 

1.2、获取全局的路径为TradingConfig--SearchConfig--EnableNewEditionSearch的配置(带回调):

class Program
    {
        private static bool _enableNewEditionSearch = false;
        private static IConfigService _configService = null;
        static void Main(string[] args)
        {
            AdhesiveFramework.Start();
            _configService = LocalServiceLocator.GetService<IConfigService>();
            _enableNewEditionSearch = _configService.GetConfigItemValue("TradingConfig", "SearchConfig", "EnableNewEditionSearch", false, ConfigItemValueUpdateCallback);
            Console.WriteLine(_enableNewEditionSearch);
            Console.WriteLine("Press any key to continue...");
            Console.ReadKey();
            AdhesiveFramework.End();
            Console.ReadKey();

        }
        public static void ConfigItemValueUpdateCallback(ConfigItemValueUpdateArguments args)
        {
            _enableNewEditionSearch = _configService.GetConfigItemValue("TradingConfig", "SearchConfig", "EnableNewEditionSearch", false, ConfigItemValueUpdateCallback);
            Console.WriteLine(string.Format("配置项值更改,最新值为:{0}", _enableNewEditionSearch));
        }
    }

在Web后台将配置节点的值改为False,客户端输出结果为:

image

2、列表类型的配置

List<string> games = _configService.GetConfigItemValue("TradingConfig", "SearchConfig", "Games", new List<string> {"魔兽世界","冒险岛"}, ConfigItemValueUpdateCallback);
            foreach (var game in games)
            {
                Console.WriteLine(game);
            }

输出结果:

image

以上的例子,获取的是名称为Games的列表,并且指定了包含有两个元素的列表作为默认值。第一次获取时,会自动创建名称为Games的节点,并且根据指定的默认值自动创建了名称为Games_0和Games_1的两个子节点,节点的初始值来自于默认值。如下图Web管理后台所示:

image

 

下面在Web后台向列表添加一个元素:

image

重新获取名称为Games的列表,客户端输出结果为:

image

 

3、字典类型的配置

Dictionary<string, bool> switchs = _configService.GetConfigItemValue("TradingConfig", "SearchConfig", "Switchs", new Dictionary<string,bool> {{"Equipment",true},{"Card",false} }, ConfigItemValueUpdateCallback);
            foreach (var de in switchs)
            {
                Console.WriteLine("物品类型:{0},是否开启该业务:{1}",de.Key,de.Value);
            }

输出结果:

image

以上的例子,获取的是名称为Switchs值为布尔类型的字典,并且指定了包含两个字典项的字典作为默认值。第一次获取时,会自动创建名称为Switchs的节点,并且根据指定的默认值自动创建名称为EquipmentCard的两个子节点,字典项的关键字作为节点的名称,节点的初始值来自于默认值。如下图Web管理后台所示:

image

 

下面在Web后台向字典添加一个字典项:

image

 

输出结果:

image

 

4、自定义实体类型配置

先来看一个自定义实体:

[ConfigEntity(FriendlyName="存储上下文配置")]
    public class StorageContextConfigurationEntity
    {
        [ConfigItem(FriendlyName="存储上下文集合")]
        public Dictionary<string,StorageContextConfigurationItem> StorageContexts { get; set; }
    }
    public class StorageContextConfigurationItem
    {
        [ConfigItem(FriendlyName = "存储上下文名称")]
        public string Name { get; set; }
        [ConfigItem(FriendlyName="数据提供程序名称")]
        public string ProviderName { get; set; }
        [ConfigItem(FriendlyName = "数据库连接字符串")]
        public string ConnectionString { get; set; }
    }

自定义实体可以包含一系列字段或属性,这些字段或属性可以是基础数据类型、字典、列表或者自定义实体,层级不受限制。自定义实体存在两个限制:第一,不能递归定义,也就是说自定义实体的字段或属性的类型不能和本身的类型相同,第二,自定义实体不能定义自己的构造函数。当客户端第一次获取实体类型的配置时,会根据实体的定义在后台自动创建实体的结构,并使用默认值初始化。为了在Web管理后台能直观的了解自定义实体及其字段或属性的具体含义和描述信息,可以通过使用ConfigEntityAttribute属性和ConfigItemAttribute属性的FriendlyNameDescription字段来指定。

调用示例:

_defaultConfig = new StorageContextConfigurationEntity
                                    {
                                        StorageContexts = new Dictionary<string, StorageContextConfigurationItem>
                                         {
                                             {Constants.DefaultContextName,
                                          new  StorageContextConfigurationItem
                                               {
                                                   Name = Constants.DefaultContextName,
                                                   ProviderName = "System.Data.SqlClient",
                                                   ConnectionString = "Server=.;Database=Adhesive;User ID=sa;Password=DLdNa9R+IFkkHxvWszyLHw==;Trusted_Connection=False;Persist Security Info=True",
                                               }}
                                         }
                                    };
            _storageContextConfig = _configService.GetConfigItemValue(true, "StorageContextConfigurationEntity", _defaultConfig);

 

我们来看下Web管理后台:

第一级配置:

image

 

第二级配置:

image

 

第三级配置:

image

 

第四级配置:

image

我们可以看到,自定义实体的结构在后台中自动创建出来了,并且设置了默认值。

 

下面我们来向存储上下文集合中添加一个存储上下文:

image

 

image

 

image

我们可以看到,StorageContexts 集合下新加了一个名为OrderContext的存储上下文。存储上下文是一个实体类,下面包含三个属性,由于StorageContexts 集合有一个默认值DefaultContext,并且初始化的时候其结构也被自动创建了。这样一来在添加OrderContextde 的时候就知道了实体结构,会将DefaultContext的结构复制过来然后再根据需要修改相应字段的值就可以了这也是设置初始值的好处。如果没有设置初始值,在向元素类型为实体的列表或字典中添加一个元素时,就需要手工建立实体的结构。建议在实际使用中设置初始值,减少输入工作量。

好了,配置服务模块的使用本次就介绍到这里,在下一篇文章中会详细介绍实现的原理。

posted @ 2011-10-12 15:42  陈 锋  阅读(1561)  评论(1编辑  收藏  举报