3

サード パーティのアセンブリを必要とするスクリプト タスクを含む SSIS パッケージがあります。このアセンブリを SSIS サーバーの GAC に配置することは許可されていないため、スクリプト タスクの静的コンストラクターで実行時にアセンブリをバインドしています。この記事は、私がガイドラインとして使用したものです。ただし、アセンブリ ファイルへのパスのハードコーディングを回避する方法を見つけたいと考えています。

私の作業コードは次のようになります。

  static ScriptMain()
     {
         AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
     }
     static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
     {
         if (args.Name.Contains("thirdparty"))
         {
             string path = @"C:\mydrive\Solution\Reference";
             return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "thirdparty.dll"));
         }
         return null;
     }

私が試したこと:

1) パスをパッケージ変数として設定します。静的コンストラクターの実行時に Dts オブジェクトがまだインスタンス化されておらず、パッケージ変数にアクセスできないため、これは機能しません。

2) 次のようにアセンブリ解決イベントを発生させているアプリ ドメインにアクセスしようとしました。

string appDomainPath = ((AppDomain)sender).BaseDirectory;

ただし、これは VSTA コードが存在するディレクトリを取得するだけです。

私はアイデアがありません。これは可能ですか?

4

3 に答える 3

1

Environment を使用して、パッケージ変数を静的コンストラクターに忍び込ませることができます。

「初期化」スクリプト タスクで、Main():

Environment.SetEnvironmentVariable("LIBRARY_PATH", Dts.Variables["$Package::LIBRARY_PATH"].Value.ToString(), EnvironmentVariableTarget.Process);

その後、将来のどこでも スクリプト コンポーネント/タスク

        static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            string library_path = Environment.GetEnvironmentVariable("LIBRARY_PATH", EnvironmentVariableTarget.Process);
            /* ...
               ... */
        }

ノート:

  • 環境に基づいてオーバーライドし、SQL Server エージェントを介して設定できるため、パッケージ変数を使用することをお勧めします。
  • アセンブリを必要としない最初のタスクでは、パスを EnvironmentVariable に貼り付け、DTS アクセスを持つ Main() を使用して (他の同時実行へのリークを防ぐために) プロセスをスコープに設定します。
  • これですべてです。努力を惜しみません... ライブラリ パスは、他のすべてのダウンストリーム タスクの静的コンストラクターでアクセスできるようになります。
于 2019-11-20T01:32:39.463 に答える
0

私はこれを達成しました - VB では残念ですが、C# に簡単に変換できるはずです。

あなたが参照した記事から、私を正しい軌道に乗せたポイントはこれでした:

秘訣は、.NET の Just-in-Time (JIT) コンパイルが依存アセンブリの読み込みを担当していることを理解することです。したがって、型のメソッドで参照されるアセンブリは、メソッドが実行される直前まで読み込まれないことが保証されます。

したがって、私のスクリプト タスクは次のようになります。

' See the Main() task, where this is set
Public Shared referencePath As String

Public Sub New()
    AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf CurrentDomain_AssemblyResolve
End Sub

''' <summary>
''' The Ionic.zip reference isn't in the GAC, so we need to give the assembly resolver a hint as to where it resides:
''' </summary>
''' <param name="sender"></param>
''' <param name="args"></param>
''' <returns></returns>
Private Shared Function CurrentDomain_AssemblyResolve(ByVal sender As Object, ByVal args As ResolveEventArgs) As Reflection.Assembly
    If args.Name.ToLower.Contains("ionic.zip") Then
        Return Reflection.Assembly.LoadFile(Path.Combine(referencePath, "Ionic.zip.dll"))
    End If

    Return Nothing
End Function

Public Sub Main()
    ' Set the static referencePath to our SSIS variable's value - we need to do this because the Ionic.Zip reference,
    ' referred to in the ProcessEmails() method, will otherwise look in the GAC, and won't find what it's looking for.
    referencePath = Dts.Variables("ReferencePath").Value.ToString()

    Dts.TaskResult = ProcessEmails()
End Sub

ProcessEmails() メソッド本体は含めていませんが、これは Main() タスクが現在実行していることを単純に実行します。

このように、アセンブリ リゾルバーは ProcessEmails() メソッドが呼び出されるまでサード パーティのアセンブリを解決しようとせず、Main() にそれを Dts.Variable に設定する機会を与えます。

GAC にサードパーティの DLL がない SQL 2017 環境でテストされ、動作しています。

于 2019-12-02T09:37:00.187 に答える