对服务来讲,通常都会用到数据库。而今,在微软的大环境下,使用 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
另外,上面这段代码缺点东西,自行脑补吧,很容易就看明白的。插件