2

デフォルト (完全信頼) の AppDomain で、サンドボックス AppDomain を作成し、その中のイベントをサブスクライブしたいと考えています。

class Domain : MarshalByRefObject
{
    public event Action TestEvent;
}

Domain domain = AppDomainStarter.Start<Domain>(@"C:\Temp", "Domain", null, true);
domain.TestEvent += () => { }; // SecurityException

サブスクリプションが失敗し、「タイプ 'System.Security.Permissions.ReflectionPermission, mscorlib, Version=4.0.0.0...' のアクセス許可の要求が失敗しました」というメッセージが表示されます。

(AppDomainStarter の定義については、別の質問に対する私の回答を参照してください。)

ApplicationBase C:\Tempは、ドメインを含むアセンブリを含むフォルダーではないことに注意してください。これは意図的なものです。私の目標は、新しい AppDomain 内に 2 番目のサードパーティの信頼されていないアセンブリを読み込むことです。この 2 番目のアセンブリは C:\Temp (または他の場所、場合によってはネットワーク共有) にあります。Domainただし、2 番目のアセンブリを読み込む前に、新しい AppDomain 内にクラスを読み込む必要があります。これは成功しますが、何らかの理由で AppDomain 境界を越えてイベントをサブスクライブできません (メソッドを呼び出すことはできますが、イベントをサブスクライブすることはできません)。

UPDATE : 明らかに、サンドボックス AppDomain でイベントをサブスクライブする場合、サブスクライバー メソッドとサブスクライバーを含むクラスの両方がパブリックである必要があります。例えば:

public static class Program
{
    class Domain : MarshalByRefObject
    {
        public event Action TestEvent;
        public Domain() { Console.WriteLine("Domain created OK"); }
    }
    static void Main()
    {
        string loc = @"C:\Temp";
        Domain domain = AppDomainStarter.Start<Domain>(loc, "Domain", null, true);
        // DIFFERENT EXCEPTION THIS TIME!
        domain.TestEvent += new Action(domain_TestEvent);
    }
    public static void domain_TestEvent() { }
}

しかし、私はまだイベントにサブスクライブできません。新しいエラーは、「ファイルまたはアセンブリ 'TestApp、Version=1.0.0.0、Culture=neutral、PublicKeyToken=null' またはその依存関係の 1 つを読み込めませんでした。指定されたファイルが見つかりません」です。

新しい AppDomain の ApplicationBase として「間違った」フォルダ「C:\Temp」を指定したため、これはある意味では理にかなっていますが、「TestApp」アセンブリが両方の AppDomain に既に読み込まれているため、ある意味でこれはまったく意味がありません。 . CLR が既に読み込まれているアセンブリを見つけられない可能性はありますか?

さらに、アセンブリを含むフォルダーへのアクセス許可を追加しても違いはありません。

string folderOfT = Path.GetFullPath(Path.Combine(typeof(T).Assembly.Location, ".."));
permSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read, folderOfT));
// Same exception still occurs

に別の値を使用して問題を「修正」できますAppDomainSetup.ApplicationBase

string loc = Path.GetFullPath(Assembly.GetExecutingAssembly().Location + @"\..");

これにより例外は排除されますが、AppDomain の目的は、独自のアセンブリを含むフォルダーとは別のフォルダーから信頼されていないアセンブリを読み込むことであるため、この "解決策" を使用できません。したがって、loc自分のアセンブリを含むフォルダーではなく、信頼されていないアセンブリを含むフォルダーである必要があります。

4

3 に答える 3

0

例外は、完全な信頼ドメインではなく、部分的な信頼ドメインからのものです。部分信頼ドメインでReflectionPermissionを付与することを省略している必要があります

于 2012-01-22T20:07:41.767 に答える
0

動作することがわかった唯一の方法は、アセンブリ (新しい AppDomain で実行するコードを含む) を GAC に入れることです。もちろん、これはお尻の大きな痛みですが、機能するのはこれだけです。

以下に、私が試してうまくいかなかったいくつかのことを説明します。

場合によっては、Visual Studio 2010 で Activator.CreateInstanceFrom を呼び出したときに次のメッセージが表示されます (正確なタイミングはわかりません。クリーンなコンソール アプリではこれは生成されません)。

マネージ デバッグ アシスタント 'LoadFromContext' は、'C:\Users...\TestApp.vshost.exe' で問題を検出しました。追加情報: LoadFrom コンテキストを使用して、'TestApp' という名前のアセンブリが 'file:///C:/Users/.../TestApp.exe' から読み込まれました。このコンテキストを使用すると、シリアル化、キャスト、および依存関係の解決で予期しない動作が発生する可能性があります。ほとんどの場合、LoadFrom コンテキストを避けることをお勧めします。これを行うには、グローバル アセンブリ キャッシュまたは ApplicationBase ディレクトリにアセンブリをインストールし、アセンブリを明示的に読み込むときに Assembly.Load を使用します。

Assembly.LoadFromのドキュメントには、次のステートメントが含まれています。デシリアライズされています。」残念ながら、これがなぜ起こるのかについてのヒントはありません。

サンプル コードでは、Assemblyは逆シリアル化されていません (そもそも Assembly を逆シリアル化することの意味がよくわかりません) が、デリゲートは逆シリアル化されています。デリゲートの逆シリアル化には、同じアセンブリを "表示名で" 読み込もうとする試みが含まれると仮定するのが妥当です。

これが当てはまる場合、デリゲートが "LoadFrom コンテキスト" を使用して読み込まれたアセンブリ内にある関数を指している場合、AppDomain の境界を越えてデリゲートを渡すことはできません。その場合、CreateInstance代わりにを使用するとCreateInstanceFrom、この問題を回避できます (CreateInstanceFromを使用するためLoadFrom):

return (T)Activator.CreateInstance(newDomain,
    typeof(T).Assembly.FullName,
    typeof(T).FullName, false,
    0, null, constructorArgs, null, null).Unwrap();

しかし、これはニシンであることが判明しました。がアセンブリを含むフォルダーに設定されていCreateInstanceない限り使用できません。IS がそのフォルダーに設定されている場合、新しい AppDomain で T を作成するために使用されたかどうかに関係なく、 TestEvent へのサブスクライブは成功します。したがって、T が経由でロードされたという事実だけで問題が発生するわけではありません。ApplicationBaseApplicationBaseCreateInstanceCreateInstanceFromLoadFrom

私が試したもう 1 つのことは、アセンブリに署名し、.NET Framework に完全な信頼を与えるように指示することでした。

newDomain = AppDomain.CreateDomain(appDomainName, null, setup, permSet,
    new StrongName[] { GetStrongName(typeof(T).Assembly) });

これは、MSDN の記事の GetStrongName メソッドに依存しています。残念ながら、これは何の効果もありません (つまり、依然として FileNotFoundException が発生します)。

于 2012-03-07T22:38:33.313 に答える
0

アセンブリは AppDomain ごとに解決されます。別のディレクトリで新しい AppDomain を開始しているため (およびアセンブリが GAC に登録されていないため)、アセンブリを見つけることができません。AppDomainStarter コードを変更して、最初に対象のアセンブリを読み込み、次にそのアセンブリからインスタンスを作成できます。

            Assembly assembly = Assembly.LoadFrom(typeof(T).Assembly.ManifestModule.FullyQualifiedName);
        return (T)assembly.CreateInstance(typeof(T).FullName, false, 0, null, constructorArgs, null, null);
于 2012-03-06T07:17:02.293 に答える