2017-02-10 170 views
0

我希望能够在运行时加载数据库驱动程序程序集并执行到服务器的连接。.net core:在运行时加载程序集及其非托管依赖关系

例如,在一个控制台应用程序我想从我的NuGet包加载SQLite的驱动和负载类型:SqliteConnection。在这里我的伪代码:

string path = Path.Combine(NugetPackagesDir, @"microsoft.data.sqlite\1.1.0\lib\netstandard1.3\Microsoft.Data.Sqlite.dll"); 
var myAssembly = AssemblyLoadContext.Default.LoadFromAssemblyPath(path); 
var myType = myAssembly.GetType("Microsoft.Data.Sqlite.SqliteConnection"); 
IDbConnection cnn = (IDbConnection)Activator.CreateInstance(myType); 
cnn.ConnectionString = "Data Source=:memory:"; 
cnn.Open(); 

它的工作原理,直到cnn.Open()点,它失败找到一个非托管的依赖:

System.DllNotFoundException: '无法加载DLL' 的sqlite3 “

我有与SQL Server和本地依赖相同的行为:

System.DllNotFoundException:“无法加载DLL‘如果我复制DLL在它工作的驱动程序包,但我觉得这种想法不便于sni.dll’


UPDATE

我不知道的前期哪些类型的DbConnection我有实例,也没有我的操作系统。

上下文是我的库实现了Microsoft.Build.Utilities.Task,并且在项目构建后由MsBuild.exe启动。 所以我有$(TargetPath)我想要DbConnection(和驱动程序程序集名称在配置文件或其他地方)的应用程序。

在.NET世界中,所有程序集(托管或不)都位于调试/发布文件夹$(TargetPath)或GAC中。 但在.net核心,我只有deps.json文件。

所以我的猜测:使用DependencyContext类读取deps.json文件。 查找它使用的数据库驱动程序,并将该程序集及其所有依赖项(取决于操作系统)复制到临时文件夹中,最后我可以实例化DbConnection类。


更新2

我的目标是能够,建造后,要运行的使用NuGet包我开发的应用程序的SQL迁移脚本。 所以我的代码在MSBuild任务内部运行,而不是在目标应用程序中运行。

生成后,MsBuild任务加载目标项目app.config文件(for。NET),这应该申报像一些变量:在项目

  • 连接字符串
  • 迁移脚本文件夹(S)使用

    • 数据库驱动程序...

    有了这些数据然后我创建一个DbConnection并运行在指定文件夹中找到的脚本。

  • +0

    你能澄清几件事吗?这个MSBuild任务将如何使用?它将如何确定使用哪种类型的DbConnection?连接字符串从哪里来?一个正确的实现将取决于你是否试图从MSBuild正在编译的应用程序运行代码,或者只是试图在构建步骤中运行MSBuild内的某些东西。 – natemcmaster

    +0

    我更新了我的答案。你想要做的是很难的。我提出了一个更简单的方法,但是一个完整的解决方案在堆栈溢出答案中描述得太长。 – natemcmaster

    回答

    0

    最简单的方法是让运行时自动为你装载程序集。不要调用Assembly.Load。相反,请将对Microsoft.Data.Sqlite和System.Data.SqlClient NuGet包的引用添加到项目中。随着的csproj和VS 2017年,这看起来像:

    <PackageReference Include="Microsoft.Data.Sqlite" Version="1.1.0" /> 
    <PackageReference Include="System.Data.SqlClient" Version="4.3.0" /> 
    

    如果使用project.json,它是

    { 
        "dependencies": { 
         "Microsoft.Data.Sqlite": "1.1.0", 
         "System.Data.SqlClient": "4.3.0" 
        } 
    } 
    

    然后,添加的DbConnection的不同实现之间切换的一类。

    public class MyConnectionFactory 
    { 
        public DbConnection Create(string serverType, string connectionString) 
        { 
         if (serverType == "sqlite") return new SqliteConnection(connectionString); 
         else if (serverType == "sqlserver") return new SqlConnection(connectionString); 
    
         throw new ArgumentException($"{serverType} not supported"); 
        } 
    } 
    

    试图自己实现组装加载逻辑会让你处于一个你不想要的伤害世界。坚持使用NuGet包。

    这是有问题的,当然,如果您不知道什么DbConnection你想要的种类。如果这是您的场景,那么您需要将NuGet缓存中的所有非托管和托管库复制到应用程序基目录(程序集的位置与Program.Main)中。如果您希望.NET Core在多个操作系统(Linux,macOS)和平台(x86,x64,ARM)上运行,这不是一种推荐的方法,并且不起作用。

    编辑

    与非托管代码内的MSBuild将是非常困难的,因为是的MSBuild控制主机与组件装载可能执行。您可能会发现一个更简单的解决方案是从MSBuild启动一个新的.NET Core进程到调用DbConnection的控制台应用程序。

    +0

    谢谢Nate!我已经指定了我的问题。我做得很好吗? –

    相关问题