2017-02-10 126 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!我已經指定了我的問題。我做得很好嗎? –

    相關問題