2013-07-24 11 views
5

バイト配列だけを使用してアセンブリをロードすることを試していますが、正しく動作させる方法を理解できません。ここでの設定は次のとおりです。バイト配列アセンブリのロード

public static void Main() 
{ 
    PermissionSet permissions = new PermissionSet(PermissionState.None); 
    AppDomainSetup setup = new AppDomainSetup { ApplicationBase = Environment.CurrentDirectory }; 
    AppDomain friendlyDomain = AppDomain.CreateDomain("Friendly", null, setup, permissions); 

    Byte[] primary = File.ReadAllBytes("Primary.dll_"); 
    Byte[] dependency = File.ReadAllBytes("Dependency.dll_"); 

    // Crashes here saying it can't find the file. 
    friendlyDomain.Load(dependency); 

    AppDomain.Unload(friendlyDomain); 

    Console.WriteLine("Stand successful"); 
    Console.ReadLine(); 
} 

私は2つのモックDL​​Lを作成し、システムは物理的なファイルを見つけることができないように、意図的に「.dll_」に自分の拡張子の名前を変更しました。 primarydependency塗りつぶし正しく、私はバイナリデータでAppDomain.Loadメソッドを呼び出すしようとすると、それはして戻ってくる両方:それは、ファイルシステムを検索することになるのはなぜ

Could not load file or assembly 'Dependency, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

UPDATE

この一方で動作するようです:

public class Program { 
    public static void Main() { 
     PermissionSet permissions = new PermissionSet(PermissionState.Unrestricted); 
     AppDomainSetup setup = new AppDomainSetup { ApplicationBase = Environment.CurrentDirectory }; 
     AppDomain friendlyDomain = AppDomain.CreateDomain("Friendly", null, setup, permissions); 

     Byte[] primary = File.ReadAllBytes("Primary.dll_"); 
     Byte[] dependency = File.ReadAllBytes("Dependency.dll_"); 

     // Crashes here saying it can't find the file. 
     // friendlyDomain.Load(primary); 

     Stage stage = (Stage)friendlyDomain.CreateInstanceAndUnwrap(typeof(Stage).Assembly.FullName, typeof(Stage).FullName); 
     stage.LoadAssembly(dependency); 

     Console.WriteLine("Stand successful"); 
     Console.ReadLine(); 
    } 

} 

public class Stage : MarshalByRefObject { 
    public void LoadAssembly(Byte[] data) { 
     Assembly.Load(data); 
    } 
} 

だから、AppDomain.LoadAssembly.Loadに差がある表示されます。

+0

依存関係DLLにはコピーされていない依存関係はありますか? –

+0

プライマリは依存関係に依存します。依存関係には(CLR以外の)依存関係はありません。ランタイムのように開始するファイルを検索していないように見えます。 – sircodesalot

答えて

9

これは正常で、CLRは、「依存関係」あなたは「主」必要があること、それがアセンブリを検索する際に、適切なアセンブリするロードを考慮しません。 "ロードコンテキスト"に関連する問題は、このようにロードされたアセンブリのためのものはありません。これは意図的なもので、アセンブリがどこから来たのか分からないため、CLRはDLL Hellが問題にならないようにすることはできません。あなたはDLL地獄への扉を開いたので、地獄も避けなければなりません。

AppDomain.AssemblyResolveイベントを実装する必要があります。 CLRが "依存"を見つけることができないときに起動し、Assembly.Load(byte [])から取得したアセンブリを返すことができます。ただし、同じアセンブリに対して複数回起動すると、まったく同じアセンブリが返されるため、一貫して実行する必要があります。そうしないと、.NETの型識別によって多くの問題が発生します。キャスティングの例外を理解するのが難しい、「FooをFooにキャストできません」というスタイル。

他の問題がありますが、それはむしろ非効率的です。アセンブリの仮想メモリは、ディスク上のファイルでバックアップすることはできません。そのため、ページングファイルによってバックアップされます。プロセスのコミット・サイズを増加させます。

これを実行しないことをお勧めします。

+0

なぜ 'Assembly.Load'はこれを許可しているようですが、' AppDomain.Load'は許可していませんか?また、コミットサイズのポイントが良い。 – sircodesalot

+0

Assembly.Loadとは何の関係もありません。 AssemblyResolveを使用すると、CLRは「これが必要です」と言って、「ここにいる」と言います。だからCLRはそれが何を持っているか知っています。あなたの元のアプローチは「ここに何か」であり、CLRは「それが何であるかわからない」と言っています。 –

+0

私はあなたが言っていることに従いますが、方法を切り替えるだけでうまくいくようです。 AssemblyResolveを使用する必要はありませんでした。なぜならCLRはAssembly.Loadから来たときにそれを受け入れたからです。 – sircodesalot

0

あなたはCLRアセンブリをロードするには持っている特定の問題の詳細を見ることができますFusionLogViewer ....それはあなたの手掛かりを与えるために、プローブしようとしている場所をお見せすることができます使用している場合など

あなたはまた、シーケンスをトレースするために、あなたのコードでは、あなたの AppDomainのAssemblyLoad /に、AssemblyResolve/ResourceResolveイベントを処理することができ

これはあなたのEXEプログラムにリソースとしてプロジェクト依存アセンブリのいずれかを埋め込んで、その後、(ResourceStreamからそれらをロードするためにAssemblyResolveを使用するカスタムMSBuildのステップを使用して便利な例です。 byte []配列に対してAssembly.Load()を実行します)。

+0

'プローブしようとしている場所を表示できます。それはちょうどそれ、それはのように思えるはずはありません。私はすでにバイナリを指定しているので、ファイルシステムから外して再度ロードする必要はありません。 – sircodesalot

+0

'Primary 'は' Dependency'に依存します。 'AppDomain.Load'はうまく動作しないようですが、' AppDomain.Load'はうまく動作していないようです。 – sircodesalot

3

これらの2つの方法には違いはありません(必要に応じてofficial source codeを確認できます)。

この方法は、現在 アプリケーションドメインにアセンブリをロードするためにのみ使用されるべきである:MSDNページで

AppDomain.Load Method (Byte[])ため、この方法は、現在のアプリケーションドメインにアセンブリをロードしていることが注目されます。このメソッドは、静的なAssembly.Load メソッドを呼び出せない、相互運用性の呼び出し元 の便宜のために提供されています。アセンブリを他のアプリケーションドメインに読み込むには、CreateInstanceAndUnwrapなどの メソッドを使用します。

ライン:Stageオブジェクトは、実際に内部Assembly.Loadを呼び出しているためで、

Assembly.Load(dependency); 

それはあなたの更新のサンプルコードで働く理由:

friendlyDomain.Load(dependency); 

はと全く同じ動作をします AppDomain。

注:この回答は、Hans Passantとcolinsmithの回答を補完します。

+0

私は最終的に、アセンブリをディスク上の一時フォルダに保存して、そのフォルダに 'AppDomain'ベースを設定することに決めました。私は狂っているかもしれませんが、 'AppDomain.Load'はアセンブリの物理的な存在をディスクでチェックしているのに対し、' Assembly.Load'はそうではないようです。実際、私の現在の実装では、アセンブリの完全な名前を 'friendlyDomain.Load'に渡し、' ApplicationBase'から期待通りにそれを取り出します。しかし、なぜそれがバイト配列を確認せずに取ることはない私の外です。 – sircodesalot