WebApi 插件式構建方案:集成加載數據庫鏈接字符串

對服務來講,通常都會用到數據庫。而今,在微軟的大環境下,使用 EF 的人確定會愈來愈多。可是,使用 EF 有個問題,一個是使用缺省的構造函數,缺省從 ConfigurationManager.ConnectionStrings 中獲取數據庫鏈接;另一種就是在構造的時候,手工指定數據庫鏈接字符串。html

對開發者來講,最好的辦法就是不去管它,直接用缺省的構造函數就好。可是插件式的開發,系統怎麼知道你數據庫的鏈接字符串放在哪呀?主要的問題就在於其數據庫鏈接字符串,並無添加到 Web.Config 文件中,因此使用缺省構造函數,會出現沒法找到配置的錯誤。web

有個最簡單的解決辦法:能夠選擇把數據庫鏈接字符串放到 Web.config 中,這樣就能解決全部問題。可這樣作,插件的配置侵入到主站了!可是,話說回來,我相信大部分用 WebApi 框架的人,都是這樣乾的。這樣用,往後模塊本身的數據庫鏈接字符串增刪改升級的時候,還得更改主站的配置。數據庫

這是繞不過去的一個坎!把原本一個的配置分散到兩個地方,每次變更就必須修改這兩處地方。往後維護的時候,這就是個坑!在知道的人離職後,後續的人根本就找不到問題緣由。markdown

插件管理本身的數據庫鏈接字符串

理想的狀況下,咱們能夠在第一次系統初始化的時候,給 ConfigurationManager.ConnectionStrings 這個集合中添加咱們的數據庫配置,這樣就能在解析的時候找到配置了。順着這個思路繼續想,微軟的反射很強大,能夠更改原本不能夠更新的數據。因此,就有了下面這段代碼:app

public void Configurate(System.Configuration.Configuration[] configurations)
{
    var meta = ((TypeX)ConfigurationManager.ConnectionStrings.GetType()).GetField("bReadOnly");
    meta.SetValue(ConfigurationManager.ConnectionStrings, false);

    configurations.SelectMany(p => p.ConnectionStrings.ConnectionStrings.OfType<ConnectionStringSettings>())
                  .Where(p => ConfigurationManager.ConnectionStrings.IndexOf(p) < 0)
                  .ForEach(ConfigurationManager.ConnectionStrings.Add);

    meta.SetValue(ConfigurationManager.ConnectionStrings, true);
}

這段代碼的意思是,把各個模塊的數據庫鏈接字符串文件加載到列表中,而後經過反射開啓賦值,加到 ConfigurationManager.ConnectionStrings 集合中。框架

要完成這個功能,咱們尚需作的就是找到每一個模塊的數據庫鏈接字符串文件,而後加載得到上面這個函數的參數。考慮到咱們爲每一個模塊定義了一個配置文件,因此這裏爲其添加一個配置就行了:函數

<?xml version="1.0" encoding="UTF-8"?>
  <configuration enabled="true">
    <description>受權支持插件</description>
    <assemblies>
      <add type="relative">bin/Intime.AuthorizationService.dll</add>
      <add type="relative">bin/Intime.AuthorizationService.Services.dll</add>
      <add type="relative">bin/Intime.AuthorizationService.Data.dll</add>
      <add type="relative">bin/Intime.AuthorizationService.Data.Repository.dll</add>
    </assembiles>
    <appConfig type="relative">bin/Intime.AuthorizationService.Data.Repository.dll.config</appConfig>
</configuration>

參考 appConfig 配置節,咱們能夠獲得模塊的配置文件絕對路徑,再和 DynamicModules 配合,用下面這段代碼就能夠獲得 System.Configuration.Configuration[] configurations 這個參數了:url

public void Configurate(HttpConfiguration configuration)
{
    var items = ServiceLocator.Current.GetAllInstances<IAppConfigHandler>().ToArray();
    if (items.Any())
    {
        var data = DynamicModules.Instance
            .Modules
            .Where(p => !string.IsNullOrWhiteSpace(p.Configuration.AppConfig))
            .Select(p =>
            {
                var fullFilePath = Path.Combine(p.Path, p.Configuration.AppConfig);

                return ConfigurationManager.OpenMappedExeConfiguration(new ExeConfigurationFileMap { ExeConfigFilename = fullFilePath }, ConfigurationUserLevel.None);
            })
            .ToArray();

        items.ForEach(p => p.Configurate(data));
    }
}

能夠看到,在這裏我用了 IAppConfigHandler 接口,這樣就能夠擴展其餘的配置了,不只限於 ConnectionStringsspa

另外,上面這段代碼缺點東西,自行腦補吧,很容易就看明白的。插件

相關文章
相關標籤/搜索