【问题标题】:2 MEF plugins using Entity Framework with different providers2 MEF 插件使用实体框架和不同的提供者
【发布时间】:2018-03-22 03:53:29
【问题描述】:

我有一个 WPF 应用程序,我的用户可以使用 MEF 为其创建自己的插件。每个插件都实现了一个接口,允许主应用程序对某些数据源执行 CRUD 操作,例如一个数据库。

我创建了 2 个插件:

  • Lo​​calDatabase - 提供来自 SQLite 数据库的数据
  • RemoteDatabase - 提供来自 MySQL 数据库的数据

两者都使用实体框架来完成他们的工作。这些插件中的每一个都需要有自己的 DbConfiguration 类实现。

现在,问题是 WPF 应用程序加载了这 2 个插件,但未能为每个插件分配自己的 DbConfiguration 类实现,因为似乎每个 AppDomain 只能有一个 DbConfiguration。 所以我总是只有其中一个插件可以工作。

我在考虑只实现一个 DbConfiguration 类,并为每个插件提供一个选项来添加其所需的配置,但问题是它在 WPF 应用程序和实体框架之间创建了一些耦合。我想将实体框架的东西只保留在插件中,而不需要修改 WPF 应用程序。它不应该关心插件使用什么来访问它们的数据源。

有没有办法让它以这种方式工作?我能否以某种方式为每个插件创建一个单独的 AppDomain,这样每个插件都可以使用自己的 DbConfiguration 类?

【问题讨论】:

    标签: c# entity-framework mef


    【解决方案1】:

    我找到了一个有点 hacky 的解决方案,但它似乎确实有效,所以我想我会发布它,以防将来有人会在某个地方遇到同样的问题。

    经过一些额外的研究,我了解到您可以使用 DbConfiguration.Loaded 事件为 EF 注册一些额外的依赖关系解析器。因此,在每个插件的构造函数中,我订阅了事件并添加了一个新的依赖解析器:LocalDatabase 的 SQLite 和RemoteDatabase 的 MySql。我从每个插件中去掉了自定义的 DbConfiguration 类。

    这看起来很有希望,但实际上出现了一个新问题——在某些情况下,LocalDatabase 插件调用了 MySql 解析器,它实际上返回了所请求服务类型的 MySql 实现。显然LocalDatabase 插件无法使用它,因为它需要 SQLite 实现。反之亦然。

    因此,每个解析器实际上都需要检查谁调用了 GetService 方法 - 如果它是来自自定义解析器所在的同一程序集的某个方法,它会尝试解析。否则,假设来自不同插件的解析器应该处理该请求并返回 null 以实际让它这样做。

    问题在于GetService 方法不提供有关请求者的任何信息。所以这就是我想出 hacky 解决方案的地方,它使用 StackTrace 检查任何被调用的方法是否属于当前 Resolver 所在的同一 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;
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-11-03
      • 1970-01-01
      • 2015-10-29
      • 1970-01-01
      • 2013-10-07
      • 2013-11-11
      • 1970-01-01
      相关资源
      最近更新 更多