为啥新的 AppDomain 会加载不必要的 DLL?

Posted

技术标签:

【中文标题】为啥新的 AppDomain 会加载不必要的 DLL?【英文标题】:Why does a new AppDomain load unnecessary DLLs?为什么新的 AppDomain 会加载不必要的 DLL? 【发布时间】:2015-04-17 17:42:23 【问题描述】:

我有一个 asp.net web api,它具有执行一些动态生成的 DLL 的逻辑。 我想创建一个具有受限权限集的新沙盒 AppDomain 来执行这些 DLL。

这是创建新的受限应用域的方法:

public static AppDomain CreateRestrictedDomain(string applicationBasePath)

    PermissionSet permissionSet = new PermissionSet(PermissionState.None);
    permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
    permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.Read, applicationBasePath));

    AppDomainSetup appDomainSetup = new AppDomainSetup
    
        ApplicationBase = applicationBasePath,
        DisallowCodeDownload = true,
        DisallowBindingRedirects = true,
        DisallowPublisherPolicy = true,
        LoaderOptimization = LoaderOptimization.MultiDomainHost,
    ;


    AppDomain restrictedDomain = AppDomain.CreateDomain(
        friendlyName: "MySandbox",
        securityInfo: null,
        info: appDomainSetup,
        grantSet: permissionSet,
        fullTrustAssemblies: null);

    return restrictedDomain;

我第一次引用新的appDomain时遇到的问题,例如只是为了读取 appDomain.FriendlyName,框架会尝试将当前应用程序中存在的一些依赖项加载到新的 AppDomain。如果依赖项不在 GAC 中,它会尝试在 applicationBasePath 中找到它们,并且会失败,因为 applicationBasePath 设置为仅存储不受信任的 DLL 的文件夹。

我的问题是为什么创建一个新的 AppDomain 会触发这些额外依赖项的加载。在我上面的 CreateRestrictedDomain 方法中,没有引用任何这些依赖项。

我在 VS 2013 中使用默认模板创建了一个新的 asp.net 项目,并在索引控制器中使用上面的代码创建了一个新的 AppDomain,并打印出名称。代码如下:

public ActionResult Index()

    var tempPath = Path.GetTempPath();
    var untrustedPath = Path.Combine(tempPath, "unstrusted");
    if (!Directory.Exists(untrustedPath))
    
        Directory.CreateDirectory(untrustedPath);
    
    var appDomain = AppDomainSandboxHelper.CreateRestrictedDomain(untrustedPath);
    var friendlyName = appDomain.FriendlyName;
    ViewBag.Title = friendlyName;

    return View();

当我在调试模式下运行时,我可以看到读取 appDomain.FriendLyName 的行会触发 System.Web.dll 被加载到新的 AppDomain "MySandbox"

'iisexpress.exe' (CLR v4.0.30319: Domain 4): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_64\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll'. Symbols loaded.

'iisexpress.exe' (CLR v4.0.30319: MySandbox): Loaded 'C:\windows\Microsoft.Net\assembly\GAC_64\System.Web\v4.0_4.0.0.0__b03f5f7f11d50a3a\System.Web.dll'. Symbols loaded.

为什么 System.Web.dll 需要加载到新的 AppDomain 中?

【问题讨论】:

【参考方案1】:

securityInfo 传递null 使用当前正在执行的AppDomain 的证据。

AppDomain.CreateDomain:

安全信息

类型:System.Security.Policy.Evidence

确定在应用程序域中运行的代码的身份的证据。传递 null 以使用当前的证据 应用领域。

很可能需要加载 System.Web.dll 程序集以检查其证据。

【讨论】:

我通过了证据:Evidence evidence = new Evidence();证据.AddHostEvidence(新区域(SecurityZone.Untrusted));到方法。但这没有任何区别。我仍然可以看到 System.Web.dll 加载到新的 AppDomain 中。【参考方案2】:

原来是因为我在现有的 ASP.NET 拥有的 AppDomain 中创建了一个 AppDomain。 ASP.NET 将其自己的 AppDomainManager 安装到父 AppDomain 中,并且这会自动向下传播到子 AppDomain,除非调用者显式覆盖,如下所示

AppDomainSetup appDomainSetup = new AppDomainSetup

    ApplicationBase = applicationBasePath,
    DisallowCodeDownload = true,
    DisallowBindingRedirects = true,
    DisallowPublisherPolicy = true,
    LoaderOptimization = LoaderOptimization.MultiDomainHost,
    AppDomainManagerAssembly = "", // overridden by caller
    AppDomainManagerType = "" // overridden by caller
;

【讨论】:

以上是关于为啥新的 AppDomain 会加载不必要的 DLL?的主要内容,如果未能解决你的问题,请参考以下文章

如何在新的 AppDomain 中运行从加载到引用的程序集的方法

无法在新的 AppDomain 中创建 UserControl

为啥某些 .Net 程序集无法通过 AppDomain 的 GetAssemblies() 方法获得?

进程和 AppDomain 加载/卸载

无法在新的 appDomain 中加载程序集

在新的 AppDomain 中加载插件