你的位置:首页 > ASP.net教程

[ASP.net教程]DDD开发框架ABP之本地化资源的数据库存储扩展


      在上一篇《DDD开发框架ABP之本地化/多语言支持》中,我们知道,ABP开发框架中本地化资源存储可以采用

      以数据库的方式存储本地化资源,一个最明显的好处就是方便修改,尤其是对于基于数据库的应用系统而言,可以提供统一的维护界面。接下来我们就来一步步地实现将本地化资源存储在数据库中。

第一步 建立实体

      如果以

      为了存储资源,我们需要建立一个实体:

 1 public class DBLocalization : Entity 2 { 3   [Required] 4   [StringLength(10)] 5   public virtual string Culture { get; set; } 6   [Required] 7   [StringLength(50)] 8   public virtual string Name { get; set; } 9   [Required]10   public virtual string Value { get; set; }11 }

      其中Culture属性为语言代码,比如en, zh-TW, zh-CN等。Name属性为名称,Value属性为对应的文本。基类Entity是ABP框架提供的通用领域实体类,默认具有整型Id,且实现了IEntity接口。

第二步 建立领域服务

      领域服务提供对实体的数据操作,比如取得语言种类和语言字典。

 1 public class DBLocalizationManager : DomainService 2 { 3   private readonly IRepository<DBLocalization> _localizationRepository;  4   public DBLocalizationManager(IRepository<DBLocalization> localizationRepository)  5   { 6     _localizationRepository = localizationRepository; 7   } 8   public List<CultureInfo> GetCultures()  9   {10     return _localizationRepository.GetAllList()11     .Select(p => new CultureInfo(p.Culture))12     .Distinct()13     .ToList<CultureInfo>();14   }15   public List<DBLocalization> GetDictionary()16   {17     return _localizationRepository.GetAllList();18   }19 }

      其中IRepository<DBLocalization>以构造函数方式注入。

第三步 实现本地化资源接口(ILocalizationSource)

      ILocalizationSource是本地化框架的核心接口,接口方法包括:

      Name:资源名称,
      Initialize():初始化方法,注册时被ABP调用
      string GetString(string name) 根据名称取得文本
      IReadOnlyList<LocalizedString> GetAllStrings() 取得当前语言的全部字典清单

      ABP已经有三个实现了ILocalizationSource接口的类:NullLocalizationSource、ResourceFileLocalizationSource 和 DictionaryBasedLocalizationSource。

      把资源文本存储于数据库中,每次取得文本时都访问数据库取得数据,但基于性能的考虑,显然将资源文本提前在初始化时一次性加载到内存,应该是更好地方式。由于DictionaryBasedLocalizationSource已经实现了内存字典的通用方法,我们不太需要再另外写一个DBLocalizationSource。查看DictionaryBasedLocalizationSource代码,可以看到其构造函数需要传入一个ILocalizationDictionaryProvider的实例,这个实例用于取得本地化字典的详细内容。
      接下来我们建立一个类实现ILocalizationDictionaryProvider接口:

 1 public class DBLocalizationDictionaryProvider : ILocalizationDictionaryProvider 2 { 3   private DBLocalizationManager _dbLocalizationManager; 4   public IEnumerable<LocalizationDictionaryInfo> GetDictionaries(string sourceName) 5   { 6     if (_dbLocalizationManager == null)  7     { 8       if (IocManager.Instance.IsRegistered<DBLocalizationManager>()) 9       {10       _dbLocalizationManager = IocManager.Instance.Resolve<DBLocalizationManager>();11       }12     }13     var dictionaries = new List<LocalizationDictionaryInfo>();14     foreach (var culture in _dbLocalizationManager.GetCultures())15     {16       dictionaries.Add(17         new LocalizationDictionaryInfo(18           DBLocalizationDictionary.Build(culture.Name,19           _dbLocalizationManager.GetDictionary()) ,20           isDefault: culture.Name == ZeroConsts.DefaultLanguage21         )22       );23     }24     return dictionaries;25   }26 }

      该类实现了接口的GetDictionaries方法,取得字典对象DBLocalizationDictionary。方法首先利用依赖注入容器自动得到一个IDBLocalizationManager的实例。

      下面是DBLocalizationDictionary字典类的实现代码:

 1 public class DBLocalizationDictionary : LocalizationDictionary 2 { 3   private DBLocalizationDictionary(CultureInfo cultureInfo) 4     : base(cultureInfo) 5   { 6   } 7   public static DBLocalizationDictionary Build(string cultureName, List<DBLocalization> dictList) 8   { 9     try10     {11       var dictionary = new DBLocalizationDictionary(new CultureInfo(cultureName));12       var dublicateNames = new List<string>();13       if (dictList != null && dictList.Count>0)14       {15         foreach (DBLocalization item in dictList.FindAll(c => c.Culture == cultureName))16         {17           if (string.IsNullOrEmpty(item.Name))18           {19             throw new AbpException("name of a dictionary is empty in given data.");20           }21           if (dictionary.Contains(item.Name))22           {23             dublicateNames.Add(item.Name);24           }25           dictionary[item.Name] = item.Value.NormalizeLineEndings();26         }27       }28       if (dublicateNames.Count > 0)29       {30         throw new AbpException("A dictionary can not contain same key twice. There are some duplicated names: " + dublicateNames.JoinAsString(", "));31       }32       return dictionary;33     }34     catch (Exception ex)35     {36       throw new AbpException("Invalid localization data format! ", ex);37     }38   }39 }

第四步 注册资源

      在需要使用多语言本地化的模块,我们可以在模块的PreInitialize方法中,注册资源。一个模块可以在Configuration.Localization.Sources 集合中添加多个资源,只要实现了ILocalizationSource接口即可。

1 public override void PreInitialize()2 {3   Configuration.Localization.Sources.Add(4     new DictionaryBasedLocalizationSource("Zero", new DBLocalizationDictionaryProvider()));5 }

  到这里,将本地化资源存储在数据库中就基本上已经全部实现,剩下的就是开发界面对本地化资源进行增删改查的维护了。