我可以在 App.config

问题描述

  <entityFramework>
    <providers>
      <provider invariantName="Devart.Data.Oracle" type="Devart.Data.Oracle.Entity.OracleEntityProviderServices,Devart.Data.Oracle.Entity.EF6,Version=9.14.1204.0,Culture=neutral,PublicKeyToken=09af7300eec23701" />
      <provider invariantName="System.Data.sqlClient" type="System.Data.Entity.sqlServer.sqlProviderServices,EntityFramework.sqlServer" />
    </providers>
  </entityFramework>

我正在为应用程序 (ESRI ArcMap) 开发插件库。同时,我想使用 EF6 作为 DB Accessing。我的问题是应用程序每次执行 DbProviderFactories.GetFactory("Devart.Data.Oracle") 时都崩溃,并提示错误Devart.Data.Oracle Failed to find or load the registered .Net Framework Data Provider.

我确定所有必需的库都与主加载项 DLL 放在同一文件夹中。但是,主应用程序 exe 与加载项 DLL 不在同一位置。似乎应用程序通过单独搜索加载项文件夹来加载其加载项 DLL。

我的观察是 DbProviderFactories.GetFactory 仅在 exe 所在的文件夹中搜索提供程序 DLL。因此,它找不到位于加载项文件夹中的提供程序 DLL。我可以知道是否有任何方法可以指定 DbProviderFactories.GetFactory 应在何处搜索提供程序 DLL?

提前致谢。

解决方法

DbProviderFactories 通过代码注册:

private static void InitDbProvFactEntry() {
  bool DevartProviderRegistered = false;
  var dataSet = System.Configuration.ConfigurationManager.GetSection("system.data") as System.Data.DataSet;
  foreach (System.Data.DataRow dr in dataSet.Tables[0].Rows) {
    if ((string)dr[2] == "Devart.Data.Oracle") {
      DevartProviderRegistered = true;
    }
  }
  if (!DevartProviderRegistered) {
    dataSet.Tables[0].Rows.Add("dotConnect for Oracle","Devart dotConnect for Oracle","Devart.Data.Oracle","Devart.Data.Oracle.OracleProviderFactory,Devart.Data.Oracle,Version=" + Devart.Data.Oracle.ProductInfo.Version + ",Culture=neutral,PublicKeyToken=09af7300eec23701");
  }
}

从 YourSubDirName 加载 Devart.* 程序集:

 AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
...
    private static Assembly CurrentDomain_AssemblyResolve(object sender,ResolveEventArgs args) {

      var assemblyName = new AssemblyName(args.Name);
      if (assemblyName.Name.StartsWith("Devart.")) {
        var assembly = Assembly.GetExecutingAssembly();
        string directory = System.IO.Path.GetDirectoryName(assembly.Location);
        string newPath = Path.Combine(directory,"YourSubDirName");
        var files = Directory.EnumerateFiles(newPath);
        string targetDllName = assemblyName.Name + ".dll";
        if (files.Any(name => name.EndsWith(targetDllName))) {
          string fullFilePath = Path.Combine(newPath,targetDllName);
          return Assembly.LoadFrom(fullFilePath);
        }
      }

      return null;
    }