對服務來講,通常都會用到數據庫。而今,在微軟的大環境下,使用 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
接口,這樣就能夠擴展其餘的配置了,不只限於 ConnectionStrings
。spa
另外,上面這段代碼缺點東西,自行腦補吧,很容易就看明白的。插件