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


對服務來說,一般都會用到數據庫。而今,在微軟的大環境下,使用 EF 的人肯定會越來越多。但是,使用 EF 有個問題,一個是使用缺省的構造函數,缺省從 ConfigurationManager.ConnectionStrings 中獲取數據庫連接;另外一種就是在構造的時候,手工指定數據庫連接字符串。

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

有個最簡單的解決辦法:可以選擇把數據庫連接字符串放到 Web.config 中,這樣就能解決所有問題。可這樣做,插件的配置侵入到主站了!但是,話說回來,我相信大部分用 WebApi 框架的人,都是這樣干的。這樣用,日后模塊自己的數據庫連接字符串增刪改升級的時候,還得更改主站的配置。

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

插件管理自己的數據庫連接字符串

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

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 這個參數了:

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 接口,這樣就可以擴展其他的配置了,不僅限於 ConnectionStrings

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM