为什么我不能订阅事件在部分信任的AppDomain? [英] Why can't I subscribe to an event in a partial-trust AppDomain?

查看:294
本文介绍了为什么我不能订阅事件在部分信任的AppDomain?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的默认(完全信任)的AppDomain我想创建一个沙箱的AppDomain和订阅事件在它:

In my default (full-trust) AppDomain I want to create a sandbox AppDomain and subscribe to an event in it:

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程序,版本= 4.0.0.0 ...失败的权限。

Subscription fails with the message "Request for the permission of type 'System.Security.Permissions.ReflectionPermission, mscorlib, Version=4.0.0.0...' failed."

(对于AppDomainStarter的定义,请参见我的回答另一个问题。)

(For the definition of AppDomainStarter, see my answer to another question.)

注意 ApplicationBase C:\ TEMP 不会的包含包含域装配的文件夹。这是故意的;我的目标是加载第二个第三方不可信装配新的AppDomain中,而这第二组件位于C:\ TEMP(或任何其他地方,甚至是一个网络共享)。但在此之前,我可以载入我需要装载我的类新的AppDomain中的第二组件。这样做成功,但由于某种原因,我不能同意跨应用程序域边界的事件(我可以调用的方法,而不是订阅事件)。

Note that the ApplicationBase C:\Temp is NOT the folder that contains the assembly that contains Domain. This is deliberate; my goal is to load a second 3rd-party untrusted assembly inside the new AppDomain, and this second assembly is located in C:\Temp (or anywhere else, maybe even a network share). But before I can load the second assembly I need to load my Domain class inside the new AppDomain. Doing so succeeds, but for some reason I cannot subscribe to an event across the AppDomain boundary (I can call methods, but not subscribe to events).

更新:显然,订阅在沙箱中的AppDomain的事件,无论是用户的方法和包含该用户必须是公开的类时。例如:

UPDATE: Evidently, when subscribing to an event in a sandbox AppDomain, both the subscriber method and the class that contains the subscriber must be public. For example:

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,版本= 1.0.0.0,文化=中性公钥=空'或它的一个依赖。该系统找不到指定的文件。

However, I STILL can't subscribe to the event. The new error is "Could not load file or assembly 'TestApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified."

在某种程度上,这是有道理的,因为我指定了错误的文件夹C:\ TEMP作为我的新的AppDomain的ApplicationBase,但在某种程度上,这没有任何意义,因为TestApp装配<强>已经在这两个应用程序域。这怎么可能是CLR无法找到已加载的程序集?

In a way, this makes sense because I specified the "wrong" folder "C:\Temp" as the ApplicationBase of my new AppDomain, but in a way this makes no sense whatsoever because the "TestApp" assembly is already loaded in both AppDomains. How is it possible that the CLR cannot find an assembly that is already loaded?

此外,它没有什么区别,如果我添加的权限来访问包含我集的文件夹:

Moreover, it makes no difference if I add permission to access the folder that contains my assembly:

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的目的是从不同的文件夹,其中包含我自己集的文件夹加载不受信任的程序集。因此,位置必须是包含不可信集的文件夹,而不是包含我组装的。

This eliminates the exception, but I can't use this "solution" because the purpose of the AppDomain is to load an untrusted assembly from a different folder than the folder that contains my own assembly. Therefore, loc must be the folder that contains the untrusted assembly, not the one that contains my assembly.

推荐答案

我唯一能找到的工作原理是把组件(包含您想在一个新的AppDomain运行code)进入海关总署。当然,这是在屁股一个巨大的痛苦,但它是工作的唯一的事。

The only thing I could find that works is to put the assembly (that contains the code that you want to run in a new AppDomain) into the GAC. Of course, this is a huge pain in the butt, but it's the only thing that works.

下面我将介绍几件事情我想,没有工作。

Below I will describe a couple of things I tried that did NOT work.

在某些情况下,Visual Studio 2010中会调用Activator.CreateInstanceFrom时给你这个消息,(我不知道确切的时候 - 一个干净的控制台应用程序不会产生此):

In some circumstances, Visual Studio 2010 will give you this message when calling Activator.CreateInstanceFrom (I'm not sure when exactly--a clean console app does not produce this):

托管调试助手LoadFromContext检测到问题   在C:\用户\ TestApp.vshost.exe。其他信息:   集名为TestApp从装   文件:/// C:/Users/.../TestApp.exe使用LoadFrom上下文。使用   这种情况下可能会导致序列化意外的行为,   铸造和依赖性解析。在几乎所有的情况下,它是   建议,应避免LoadFrom上下文。这可以通过完成   在全局程序集缓存或安装组件   ApplicationBase目录和使用时的Assembly.Load明确   加载程序集。

Managed Debugging Assistant 'LoadFromContext' has detected a problem in 'C:\Users...\TestApp.vshost.exe'. Additional Information: The assembly named 'TestApp' was loaded from 'file:///C:/Users/.../TestApp.exe' using the LoadFrom context. The use of this context can result in unexpected behavior for serialization, casting and dependency resolution. In almost all cases, it is recommended that the LoadFrom context be avoided. This can be done by installing assemblies in the Global Assembly Cache or in the ApplicationBase directory and using Assembly.Load when explicitly loading assemblies.

Assembly.LoadFrom 的文档包括这样一句话:如果装配装有LoadFrom,后来在负载情况下的程序集尝试加载[中]相同的组件按显示名称,负载尝试失败。当一个程序集反序列可能发生这种情况。可悲的是,没有一丝有关的为什么的这种情况。

The documentation of Assembly.LoadFrom includes this statement: "If an assembly is loaded with LoadFrom, and later an assembly in the load context attempts to load [the] same assembly by display name, the load attempt fails. This can occur when an assembly is de-serialized." Sadly, there is no hint about why this happens.

在这个例子code,一个的组装的没有被反序列化(我不完全知道这意味着什么,以反序列化大会摆在首位),但委托的反序列化;这是合理的假设,反序列化委托涉及企图按显示名称来加载相同的组件。

In the example code, an Assembly is not being deserialized (and I'm not totally sure what it means to deserialize an Assembly in the first place), but a delegate is being deserialized; it's reasonable to hypothesize that deserializing a delegate involves an attempt to load the same assembly "by display name".

如果这是真的,这将是不可能通过一个委托跨越AppDomain的边界,如果该委托指向位于该用的是LoadFrom上下文加载程序集的功能。在这种情况下,使用的CreateInstance 而不是 CreateInstanceFrom 能避免这个问题(因为的 CreateInstanceFrom 使用 LoadFrom ):

If this were true, it would not be possible to pass a delegate across AppDomain boundaries if the delegate points to a function that is located in an Assembly that was loaded using the "LoadFrom context". In that case, using CreateInstance instead of CreateInstanceFrom could avoid this problem (because CreateInstanceFrom uses LoadFrom):

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

但是,这原来是一个红色的鲱鱼; 的CreateInstance 不能被使用,除非 ApplicationBase 设置为一个包含我们的组件,文件夹,如果 ApplicationBase 设置为该文件夹,然后订阅TestEvent成功的无论的是否的CreateInstance CreateInstanceFrom 被用来在新的AppDomain创建吨。因此,T时通过 LoadFrom 加载的事实并不全部由自己造成的问题。

But this turns out to be a red herring; CreateInstance cannot be used unless the ApplicationBase is set to the folder that contains our assembly, and if ApplicationBase IS set to that folder, then subscribing to TestEvent succeeds regardless of whether CreateInstance or CreateInstanceFrom was used to create T in the new AppDomain. Therefore, the fact that T was loaded via LoadFrom does not cause the problem all by itself.

另一件事我想是签署大会,并告诉.NET框架,它应该被赋予FullTrust的:

Another thing I tried was to sign the assembly and tell the .NET Framework that it should be given fulltrust:

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

这依赖于来自的MSDN文章。不幸的是,这没有任何影响(即FileNotFoundException异常仍然发生)。

This relies on the GetStrongName method from an MSDN article. Unfortunately, this has no effect (i.e. the FileNotFoundException still happens).

这篇关于为什么我不能订阅事件在部分信任的AppDomain?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆