我有一个WPF应用程序,我的用户可以使用MEF创建自己的插件。每个插件都实现了一个接口,允许主应用程序对某些数据源执行CRUD操作,例如:数据库。
我创建了2个插件:
两者都在使用Entity Framework来完成他们的工作。每个插件都需要有自己的 DbConfiguration 类的实现。
现在,问题是WPF应用程序加载了这两个插件,但未能为每个插件分配他们自己的DbConfiguration类实现,因为看起来每个AppDomain只能有一个DbConfiguration。 所以我总是只有其中一个插件工作。
我正在考虑只有一个DbConfiguration类的实现,并为每个插件提供一个选项来添加其所需的配置,但问题是它在WPF应用程序和实体框架之间创建了一些耦合。我想将实体框架内容仅保留在插件内,而无需修改WPF应用程序。它不应该关心插件用于访问其数据源的内容。
有没有办法让它以这种方式运作?我可能以某种方式为每个插件创建一个单独的AppDomain,那么也许每个人都可以使用自己的DbConfiguration类?
答案 0 :(得分:0)
我找到了一个有点hacky的解决方案,但它似乎确实有效,所以我想我会发布它,在一个不太可能的情况下,某人将来会在某个地方遇到同样的问题。
经过一些额外的研究,我了解到你可以使用DbConfiguration.Loaded
事件为EF注册一些额外的依赖性解析器。因此,在每个插件的构造函数中,我订阅该事件并添加一个新的依赖性解析器:LocalDatabase
的SQLite和RemoteDatabase
的MySql。我从每个插件中删除了自定义的DbConfiguration
类。
这看起来很有希望,但实际上出现了一个新问题 - 有些情况下LocalDatabase
插件调用了MySql解析器,它实际上返回了所请求服务类型的MySql实现。显然LocalDatabase
插件无法使用它,因为它期望SQLite实现。反之亦然。
因此,每个解析器实际上都需要检查谁调用了GetService
方法 - 如果它是自定义解析器所在的同一程序集中的某个方法,它会尝试解析。否则,假设来自不同插件的解析器应该处理该请求,并且它返回null以实际让它这样做。
问题是GetService
方法不提供有关请求者的任何信息。这就是我提出hacky解决方案的地方,它使用StackTrace
检查任何被调用的方法是否属于当前解析器所在的Assembly
。
public class CustomMySqlDbDependencyResolver : IDbDependencyResolver
{
private readonly Assembly _executingAssembly = Assembly.GetExecutingAssembly();
private readonly MySqlDependencyResolver _mySqlResolver = new MySqlDependencyResolver();
public object GetService(Type type, object key)
{
var stackTrace = new StackTrace();
StackFrame[] stackFrames = stackTrace.GetFrames().Skip(1).ToArray();
bool shouldResolve = stackFrames.Any(f => f.GetMethod().DeclaringType.Assembly.Equals(_executingAssembly));
if (!shouldResolve)
{
return null;
}
var resolvedService = _mySqlResolver.GetService(type, key);
return resolvedService;
}
public IEnumerable<object> GetServices(Type type, object key)
{
var service = GetService(type, key);
if (service != null)
{
yield return service;
}
}
}