2017-02-10 16 views
0

実行時にデータベース・ドライバー・アセンブリーをロードして、サーバーへの接続を実行できるようにします。 SqliteConnection:私は私のnugetパッケージからのSQLiteドライバをロードして、タイプをロードするコンソールアプリケーションで例えば.netコア:実行時にアセンブリーとそのアンマネージ依存関係をロードする

。ここに私の擬似コード:

System.DllNotFoundException:sqlite3の 'DLLをロードできません' を

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()ポイントまで動作します「

私は、SQL Serverとネイティブの依存関係と同じ動作を持っている:

System.DllNotFoundException:sni.dll「DLLをロードできません 『』を

私はドライバパッケージにDLLをコピーする場合、それは動作しますが、私はアイデアは便利ではありません見つけます。


UPDATE

私にはわからないアップフロントたDbConnectionの種類は、私がインスタンス化する必要があるも私が上だOS。

コンテキストは、私のライブラリはMicrosoft.Build.Utilities.Taskを実装しており、プロジェクトのビルド後にMsBuild.exeによって起動されます。 私はDbConnection(および設定ファイルや他の場所にあるドライバアセンブリ名)が必要なアプリケーションの$(TargetPath)を持っています。

.NETの世界では、すべてのアセンブリ(管理対象または非管理対象)は、デバッグ/リリースフォルダ$(TargetPath)またはGACにあります。 しかし、私はdeps.jsonファイルしか持っていません。

私の推測では、DependencyContextクラスを使用してdeps.jsonファイルを読んでください。 使用しているデータベースドライバを見つけて、最後にクラスをインスタンス化できる一時フォルダ内のアセンブリおよびすべての依存関係(osに依存)をコピーします。


UPDATE 2

私の目標は、私が開発しnugetパッケージを使用するすべてのアプリケーションのSQL移行スクリプトを実行するために、ビルドした後、できるようにすることです。 私のコードは、ターゲットアプリケーションではなく、MSBuildタスク内で実行されます。

ビルド後、MsBuildタスクはターゲットプロジェクトのapp.configファイルを(。以下のようないくつかの変数を宣言しているはずNET):プロジェクト

  • 接続文字列
  • 移行スクリプトフォルダ(複数可)で使用

    • データベースドライバを...これらのデータでは

    次に、DbConnectionを作成し、指定されたフォルダにあるスクリプトを実行します。

  • +0

    いくつかのことを明確にすることはできますか?このMSBuildタスクはどのように使用されますか?どのタイプのDbConnectionを使用するかはどのように決定されますか?接続文字列はどこから来たのですか?正しい実装は、MSBuildがコンパイルしているアプリケーションからコードを実行しようとしているか、MSBuild内で何かをビルドステップとして実行しようとしているかによって異なります。 – natemcmaster

    +0

    私は自分の答えを更新しました。あなたがしようとしていることは難しいです。私はより簡単なアプローチを提案しましたが、完全な解決策は長すぎてスタックオーバーフローの解答では説明できません。 – natemcmaster

    答えて

    0

    これを実行する最も簡単な方法は、ランタイムが自動的にアセンブリの読み込みを処理するようにすることです。 Assembly.Loadを呼び出さないでください。代わりに、Microsoft.Data.SqliteおよびSystem.Data.SqlClient NuGetパッケージの両方への参照をプロジェクトに追加します。 csprojとVS 2017で、これは次のようになります。あなたがproject.jsonを使用している場合

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

    、それはたDbConnectionの異なる実装を切り替えるクラスを追加し、その後

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

    です。

    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を持つアセンブリの場所)にコピーする必要があります。これは推奨アプローチではなく、複数のオペレーティングシステム(Linux、macOS)およびプラットフォーム(x86、x64、ARM)で.NET Coreを動作させたい場合には機能しません。おそらくMSBuildの内部アンマネージドコードで実行

    編集

    はMSBuildのホストとアセンブリローディングを制御するように非常に困難になるだろう。おそらく、MSBuildからDbConnectionを呼び出すコンソールアプリケーションに新しい.NETコアプロセスを開始するという簡単な解決策があります。

    +0

    ありがとうございました!私は私の質問を指定しました。私は良い仮定をしていますか? –

    関連する問題