逐步解說:在部分信任情節中發出程式碼

反映發出在完整或部分信任中使用相同的 API 集合,但在部分信任程式碼中,有些功能需要特殊權限。 此外,反映發出還有一項匿名裝載動態方法的功能,設計搭配部分信任使用並可供安全性透明組件使用。

注意

在 .NET Framework 3.5 之前,發出程式碼需要 ReflectionPermissionReflectionPermissionFlag.ReflectionEmit 旗標。 根據預設,此權限包含在 FullTrustIntranet 具名權限集合中,不在 Internet 權限集合中。 因此,只有在程式庫有 SecurityCriticalAttribute 屬性,同時執行了 ReflectionEmitAssert 方法,才能從部分信任使用該程式庫。 這類程式庫需要仔細的安全性檢閱,因為編碼錯誤可能會造成安全性漏洞。 .NET Framework 3.5 允許在部分信任案例中發出程式碼,而不需提出任何安全性要求,因為產生的程式碼本質上並非有權限的作業。 也就是產生的程式碼之權限不會比發出程式碼的組件還多。 這可讓發出程式碼的程式庫成為安全性透明的,並移除判斷提示 ReflectionEmit 的需要,讓撰寫安全的程式庫不需要仔細的安全性檢閱。

本逐步解說將說明下列工作:

如需在部分信任案例中發出程式碼的詳細資訊,請參閱反映發出中的安全性問題

如需這些程序所示範程式碼的完整清單,請參閱本逐步解說結尾的範例一節。

設定部分信任的位置

下列兩項程序會示範如何從您可以測試部分信任程式碼的位置設定位置。

  • 第一項程序示範如何建立沙箱應用程式定義域,程式碼在其中會獲授與網際網路權限。

  • 第二項程序顯示如何將有 ReflectionPermissionFlag.RestrictedMemberAccess 旗標的 ReflectionPermission,新增至部分信任的應用程式定義域,以便存取相同或較低信任組件中的私用資料。

建立沙箱應用程式定義域

若要建立可用部分信任執行組件的應用程式定義域,您必須使用 AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) 方法多載來建立應用程式定義域,指定將權限集授與這些組件。 指定授權集最簡單的方式,是從安全性原則擷取具名權限集。

下列程序會建立沙箱應用程式定義域,用部分信任的執行程式碼,測試發出的程式碼只能存取公用類型公用成員的案例。 後續程序示範如何新增 RestrictedMemberAccess,測試發出的程式碼可以存取非公用類型和成員的案例,而這些類型和成員所在組件具有相同或較低的權限。

建立部份信任的應用程式定義域

  1. 建立權限集,以授與沙箱應用程式定義域中的組件。 在此情況下,會使用網際網路區域的權限集。

    Evidence ev = new Evidence();
    ev.AddHostEvidence(new Zone(SecurityZone.Internet));
    PermissionSet pset = new NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev));
    
    Dim ev As New Evidence()
    ev.AddHostEvidence(new Zone(SecurityZone.Internet))
    Dim pset As New NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev))
    
  2. 建立 AppDomainSetup 物件來初始化具有應用程式路徑的應用程式定義域。

    重要

    為簡單起見,此程式碼範例會使用目前的資料夾。 若要執行實際來自網際網路的程式碼,不受信任的程式碼請使用另外的資料夾,依如何:在沙箱中執行部分信任的程式碼中所述。

    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = ".";
    
    Dim adSetup As New AppDomainSetup()
    adSetup.ApplicationBase = "."
    
  3. 建立應用程式定義域,指定應用程式定義域安裝資訊,以及在應用程式定義域中執行的所有組件授權集。

    AppDomain ad = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, null);
    
    Dim ad As AppDomain = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, Nothing)
    

    AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) 方法多載的最後一個參數可讓您指定組件集合,授與完全信任,而不是應用程式定義域的授權集。 因為這些組件位於全域組件快取,所以您不必指定應用程式使用的 .NET Framework 組件。 全域組件快取中的組件一律為完全信任。 您可以使用這個參數指定不在全域組件快取中的強式名稱組件。

將 RestrictedMemberAccess 新增至沙箱定義域

主應用程式可以允許匿名裝載的動態方法,存取組件中的私用資料,這些組件的信任層級都等於或低於發出程式碼的組件信任層級。 若要啟用此有限功能以略過 Just-In-Time (JIT) 可視性檢查,主應用程式會將具有 ReflectionPermissionFlag.RestrictedMemberAccess (RMA) 旗標的 ReflectionPermission 物件新增至授權集。

例如,主機可能會授與網際網路應用程式加上 RMA 的網際網路權限,讓網際網路應用程式可以發出程式碼,存取自己組件中的私用資料。 因為存取已限制在相同或較低信任的組件,所以網際網路應用程式無法存取完全信任組件的成員,例如 .NET Framework 組件。

注意

為防止提高權限,建構匿名裝載的動態方法時,會包含發出組件的堆疊資訊。 叫用方法時會檢查堆疊資訊。 因此,從完全信任程式碼叫用的匿名裝載動態方法,其信任層級仍限於發出組件的信任層級。

建立加上 RMA 的部份信任應用程式定義域

  1. 建立具有 RestrictedMemberAccess(RMA) 旗標的新 ReflectionPermission 物件,並使用 PermissionSet.SetPermission 方法將權限新增至授權集。

    pset.SetPermission(
        new ReflectionPermission(
            ReflectionPermissionFlag.RestrictedMemberAccess));
    
    pset.SetPermission( _
        New ReflectionPermission( _
            ReflectionPermissionFlag.RestrictedMemberAccess))
    

    權限若未包含在內,AddPermission 方法會將權限新增至授權集。 如果授權集已包含權限,指定的旗標就會新增至現有的權限。

    注意

    RMA 是匿名裝載動態方法的功能。 當一般的動態方法略過 JIT 可見度檢查時,發出的程式碼需要完全信任。

  2. 建立應用程式定義域,指定應用程式定義域安裝資訊及授權集。

    ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, null);
    
    ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, Nothing)
    

在沙箱應用程式定義域中執行程式碼

下列程序說明如何使用可在應用程式定義域中執行的方法來定義類別、如何在定義域中建立類別的執行個體,以及如何執行其方法。

在應用程式定義域中定義及執行方法

  1. 定義衍生自 MarshalByRefObject 的類別。 這可讓您在其他的應用程式定義域中建立類別的執行個體,以及跨應用程式定義域界限進行方法呼叫。 本例中的類別名為 Worker

    public class Worker : MarshalByRefObject
    {
    
    Public Class Worker
        Inherits MarshalByRefObject
    
  2. 定義公用方法,包含您想要執行的程式碼。 在此範例中,程式碼會發出簡單的動態方法、建立委派來執行方法,並叫用委派。

    public void SimpleEmitDemo()
    {
        DynamicMethod meth = new DynamicMethod("", null, null);
        ILGenerator il = meth.GetILGenerator();
        il.EmitWriteLine("Hello, World!");
        il.Emit(OpCodes.Ret);
    
        Test1 t1 = (Test1) meth.CreateDelegate(typeof(Test1));
        t1();
    }
    
    Public Sub SimpleEmitDemo()
    
        Dim meth As DynamicMethod = new DynamicMethod("", Nothing, Nothing)
        Dim il As ILGenerator = meth.GetILGenerator()
        il.EmitWriteLine("Hello, World!")
        il.Emit(OpCodes.Ret)
    
        Dim t1 As Test1 = CType(meth.CreateDelegate(GetType(Test1)), Test1)
        t1()
    End Sub
    
  3. 在您的主程式中,取得組件的顯示名稱。 當您在沙箱應用程式定義域中建立 Worker 類別的執行個體時,會使用此名稱。

    String asmName = typeof(Worker).Assembly.FullName;
    
    Dim asmName As String = GetType(Worker).Assembly.FullName
    
  4. 在您的主程式中建立沙箱應用程式定義域,如本逐步解說的第一項程序中所述。 因為 SimpleEmitDemo 方法只使用公用方法,所以您不必新增任何權限到 Internet 權限集。

  5. 在您的主程式中,在沙箱應用程式定義域中建立 Worker 類別的執行個體。

    Worker w = (Worker) ad.CreateInstanceAndUnwrap(asmName, "Worker");
    
    Dim w As Worker = _
        CType(ad.CreateInstanceAndUnwrap(asmName, "Worker"), Worker)
    

    CreateInstanceAndUnwrap 方法會在目標應用程式定義域中建立物件,傳回可以用來呼叫物件屬性和方法的 proxy。

    注意

    如果您在 Visual Studio 中使用此程式碼,則必須變更類別名稱以包含命名空間。 命名空間是專案的預設名稱。 例如,如果專案是 "PartialTrust",則類別名稱必須是 "PartialTrust.Worker"。

  6. 新增程式碼以呼叫 SimpleEmitDemo 方法。 呼叫會跨應用程式定義域界限封送處理,而程式碼則在沙箱應用程式定義域中執行。

    w.SimpleEmitDemo();
    
    w.SimpleEmitDemo()
    

使用匿名裝載的動態方法

匿名裝載動態方法與系統提供的透明組件相關聯。 因此,它們所包含的程式碼是透明的。 另一方面,一般的動態方法必須與現有的模組相關聯 (不論是直接指定或推斷的相關聯類型)),並接受該模組的安全性層級。

注意

動態方法與提供匿名裝載之組件建立關聯的唯一方法,是使用下列程序中描述的建構函式。 您不能在匿名裝載的組件中明確指定模組。

一般的動態方法可以存取相關聯模組的內部成員,或相關聯類型的私用成員。 因為匿名裝載的動態方法和其他程式碼是分開的,所以它們不能存取私用資料。 但是,它們在有限的情況下可以略過 JIT 可見度檢查,存取私用資料。 這項功能僅限於信任層級等於或低於發出程式碼組件信任層級的組件。

為防止提高權限,建構匿名裝載的動態方法時,會包含發出組件的堆疊資訊。 叫用方法時會檢查堆疊資訊。 從完全信任程式碼叫用的匿名裝載動態方法,其信任層級仍限於發出組件的信任層級。

使用匿名裝載的動態方法

  • 使用不指定相關聯模組或類型的建構函式,建立匿名裝載的動態方法。

    DynamicMethod meth = new DynamicMethod("", null, null);
    ILGenerator il = meth.GetILGenerator();
    il.EmitWriteLine("Hello, World!");
    il.Emit(OpCodes.Ret);
    
    Dim meth As DynamicMethod = new DynamicMethod("", Nothing, Nothing)
    Dim il As ILGenerator = meth.GetILGenerator()
    il.EmitWriteLine("Hello, World!")
    il.Emit(OpCodes.Ret)
    

    如果匿名裝載的動態方法只使用公用類型和方法,就不需要限制成員存取,也不必略過 JIT 可見度檢查。

    不需要特殊權限也可以發出動態方法,但發出的程式碼需要所用類型和方法要求的權限。 例如,如果發出的程式碼呼叫存取檔案的方法,它需要 FileIOPermission。 如果信任層級不包含該權限,則執行發出的程式碼時,會擲回安全性例外狀況。 這裡顯示的程式碼會發出只使用 Console.WriteLine 方法的動態方法。 因此,程式碼可以從部分信任的位置執行。

  • 或者,使用 DynamicMethod(String, Type, Type[], Boolean) 建構函式並指定 restrictedSkipVisibility 參數的 true,建立有限功能的匿名裝載動態方法以略過 JIT 可見度檢查。

    DynamicMethod meth = new DynamicMethod("",
                                           typeof(char),
                                           new Type[] { typeof(String) },
                                           true);
    
    Dim meth As New DynamicMethod("", _
                                  GetType(Char), _
                                  New Type() {GetType(String)}, _
                                  True)
    

    限制是匿名裝載的動態方法只可以存取信任層級等於或低於發出組件信任層級的組件私用資料。 例如,如果動態方法是以網際網路信任執行,它就可以存取也以網際網路信任執行的其他組件私有資料,但無法存取 .NET Framework 組件的私有資料。 .NET Framework 組件安裝在全域組件快取中,一律為完全信任。

    只有當主應用程式授權有 ReflectionPermissionFlag.RestrictedMemberAccess 旗標的 ReflectionPermission 時,匿名裝載動態方法才可以使用此有限功能略過 JIT 可見度檢查。 叫用方法時才要求此權限。

    注意

    建構動態方法時會包含發出組件的呼叫堆疊資訊。 因此,會要求發出組件的權限,而不是叫用方法的組件權限。 這可防止以提高的權限執行發出的程式碼。

    本逐步解說結尾的完整程式碼範例會示範有限成員存取的用法和限制。 其 Worker 類別有一方法,可以建立匿名裝載動態方法,有受限或不受限制略過可視性檢查的功能,而此範例會示範在不同信任層級的應用程式定義域中執行此方法的結果。

    注意

    有限略過可視性檢查是匿名裝載動態方法的功能。 當一般的動態方法略過 JIT 可見度檢查時,它們必須獲授與完全信任。

範例

描述

下列程式碼範例示範如何使用 RestrictedMemberAccess 旗標允許匿名裝載動態方法略過 JIT 可見度檢查,但僅限於所在信任層級與發出程式碼的組件信任層級相同或較低的目標成員。

此範例會定義 Worker 類別,可跨應用程式定義域界限封送處理。 此類別有兩個 AccessPrivateMethod 方法多載,可以發出和執行動態方法。 第一個多載會發出動態方法,呼叫 Worker 類別的私用 PrivateMethod方法,而且可以發出包含或不含 JIT 可見度檢查的動態方法。 第二個多載會發出動態方法,存取 String 類別的 internal 屬性 (Visual Basic 為 Friend 屬性)。

範例會使用協助程式方法來建立限於 Internet 權限的授權集,然後使用 AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) 方法多載來指定在使用此授權集的定義域中執行的所有程式碼,建立應用程式定義域。 此範例會在應用程式定義域中建立 Worker 類別的執行個體,並執行兩次 AccessPrivateMethod 方法。

  • 第一次執行 AccessPrivateMethod 方法時,會強制執行 JIT 可見度檢查。 因為 JIT 可見度檢查會阻止動態方法存取私用方法,所以叫用動態方法會失敗。

  • 第二次執行 AccessPrivateMethod 方法時,會略過 JIT 可見度檢查。 因為 Internet 授權集未授與足夠的權限以略過可見性檢查,所以動態方法在編譯時失敗。

此範例會將具有 ReflectionPermissionFlag.RestrictedMemberAccessReflectionPermission 新增至授權集。 然後,此範例會建立第二個定義域,指定將新授權集的權限授與在定義域中執行的所有程式碼。 此範例會在新的應用程式定義域中建立 Worker 類別的執行個體,並執行 AccessPrivateMethod 方法的兩個多載。

  • 執行 AccessPrivateMethod 方法的第一個多載,並略過 JIT 可見度檢查。 動態方法成功編譯並執行,因為發出程式碼的組件和包含私用方法的組件相同。 因此,信任層級是相等的。 如果包含 Worker 類別的應用程式曾有數個組件,則同樣的程序對這些組件任一個都會成功,因為它們位於相同的信任層級。

  • 執行 AccessPrivateMethod 方法的第二個多載,再次略過 JIT 可見度檢查。 這次動態方法是在編譯時失敗,因為它會嘗試存取 String 類別的 internalFirstChar 屬性。 包含 String 類別的組件為完全信任。 因此,它的信任層級高於發出程式碼的組件。

這項比較會示範 ReflectionPermissionFlag.RestrictedMemberAccess 如何啟用部分信任的程式碼,略跳過其他部分信任程式碼的可見度檢查,卻不危及信任程式碼的安全性。

程式碼

using System;
using System.Reflection.Emit;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Collections;
using System.Diagnostics;

// This code example works properly only if it is run from a fully
// trusted location, such as your local computer.

// Delegates used to execute the dynamic methods.
//
public delegate void Test(Worker w);
public delegate void Test1();
public delegate char Test2(String instance);

// The Worker class must inherit MarshalByRefObject so that its public
// methods can be invoked across application domain boundaries.
//
public class Worker : MarshalByRefObject
{
    private void PrivateMethod()
    {
        Console.WriteLine("Worker.PrivateMethod()");
    }

    public void SimpleEmitDemo()
    {
        DynamicMethod meth = new DynamicMethod("", null, null);
        ILGenerator il = meth.GetILGenerator();
        il.EmitWriteLine("Hello, World!");
        il.Emit(OpCodes.Ret);

        Test1 t1 = (Test1) meth.CreateDelegate(typeof(Test1));
        t1();
    }

    // This overload of AccessPrivateMethod emits a dynamic method and
    // specifies whether to skip JIT visiblity checks. It creates a
    // delegate for the method and invokes the delegate. The dynamic
    // method calls a private method of the Worker class.
    public void AccessPrivateMethod(bool restrictedSkipVisibility)
    {
        // Create an unnamed dynamic method that has no return type,
        // takes one parameter of type Worker, and optionally skips JIT
        // visiblity checks.
        DynamicMethod meth = new DynamicMethod(
            "",
            null,
            new Type[] { typeof(Worker) },
            restrictedSkipVisibility);

        // Get a MethodInfo for the private method.
        MethodInfo pvtMeth = typeof(Worker).GetMethod("PrivateMethod",
            BindingFlags.NonPublic | BindingFlags.Instance);

        // Get an ILGenerator and emit a body for the dynamic method.
        ILGenerator il = meth.GetILGenerator();

        // Load the first argument, which is the target instance, onto the
        // execution stack, call the private method, and return.
        il.Emit(OpCodes.Ldarg_0);
        il.EmitCall(OpCodes.Call, pvtMeth, null);
        il.Emit(OpCodes.Ret);

        // Create a delegate that represents the dynamic method, and
        // invoke it.
        try
        {
            Test t = (Test) meth.CreateDelegate(typeof(Test));
            try
            {
                t(this);
            }
            catch (Exception ex)
            {
                Console.WriteLine("{0} was thrown when the delegate was invoked.",
                    ex.GetType().Name);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("{0} was thrown when the delegate was compiled.",
                ex.GetType().Name);
        }
    }

    // This overload of AccessPrivateMethod emits a dynamic method that takes
    // a string and returns the first character, using a private field of the
    // String class. The dynamic method skips JIT visiblity checks.
    public void AccessPrivateMethod()
    {
        DynamicMethod meth = new DynamicMethod("",
                                               typeof(char),
                                               new Type[] { typeof(String) },
                                               true);

        // Get a MethodInfo for the 'get' accessor of the private property.
        PropertyInfo pi = typeof(System.String).GetProperty(
            "FirstChar",
            BindingFlags.NonPublic | BindingFlags.Instance);
        MethodInfo pvtMeth = pi.GetGetMethod(true);

        // Get an ILGenerator and emit a body for the dynamic method.
        ILGenerator il = meth.GetILGenerator();

        // Load the first argument, which is the target string, onto the
        // execution stack, call the 'get' accessor to put the result onto
        // the execution stack, and return.
        il.Emit(OpCodes.Ldarg_0);
        il.EmitCall(OpCodes.Call, pvtMeth, null);
        il.Emit(OpCodes.Ret);

        // Create a delegate that represents the dynamic method, and
        // invoke it.
        try
        {
            Test2 t = (Test2) meth.CreateDelegate(typeof(Test2));
            char first = t("Hello, World!");
            Console.WriteLine("{0} is the first character.", first);
        }
        catch (Exception ex)
        {
            Console.WriteLine("{0} was thrown when the delegate was compiled.",
                ex.GetType().Name);
        }
    }

    // The entry point for the code example.
    static void Main()
    {
        // Get the display name of the executing assembly, to use when
        // creating objects to run code in application domains.
        String asmName = typeof(Worker).Assembly.FullName;

        // Create the permission set to grant to other assemblies. In this
        // case they are the permissions found in the Internet zone.
        Evidence ev = new Evidence();
        ev.AddHostEvidence(new Zone(SecurityZone.Internet));
        PermissionSet pset = new NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev));

        // For simplicity, set up the application domain to use the
        // current path as the application folder, so the same executable
        // can be used in both trusted and untrusted scenarios. Normally
        // you would not do this with real untrusted code.
        AppDomainSetup adSetup = new AppDomainSetup();
        adSetup.ApplicationBase = ".";

        // Create an application domain in which all code that executes is
        // granted the permissions of an application run from the Internet.
        AppDomain ad = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, null);

        // Create an instance of the Worker class in the partially trusted
        // domain. Note: If you build this code example in Visual Studio,
        // you must change the name of the class to include the default
        // namespace, which is the project name. For example, if the project
        // is "AnonymouslyHosted", the class is "AnonymouslyHosted.Worker".
        Worker w = (Worker) ad.CreateInstanceAndUnwrap(asmName, "Worker");

        // Emit a simple dynamic method that prints "Hello, World!"
        w.SimpleEmitDemo();

        // Emit and invoke a dynamic method that calls a private method
        // of Worker, with JIT visibility checks enforced. The call fails
        // when the delegate is invoked.
        w.AccessPrivateMethod(false);

        // Emit and invoke a dynamic method that calls a private method
        // of Worker, skipping JIT visibility checks. The call fails when
        // the method is invoked.
        w.AccessPrivateMethod(true);

        // Unload the application domain. Add RestrictedMemberAccess to the
        // grant set, and use it to create an application domain in which
        // partially trusted code can call private members, as long as the
        // trust level of those members is equal to or lower than the trust
        // level of the partially trusted code.
        AppDomain.Unload(ad);
        pset.SetPermission(
            new ReflectionPermission(
                ReflectionPermissionFlag.RestrictedMemberAccess));
        ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, null);

        // Create an instance of the Worker class in the partially trusted
        // domain.
        w = (Worker) ad.CreateInstanceAndUnwrap(asmName, "Worker");

        // Again, emit and invoke a dynamic method that calls a private method
        // of Worker, skipping JIT visibility checks. This time compilation
        // succeeds because of the grant for RestrictedMemberAccess.
        w.AccessPrivateMethod(true);

        // Finally, emit and invoke a dynamic method that calls an internal
        // method of the String class. The call fails, because the trust level
        // of the assembly that contains String is higher than the trust level
        // of the assembly that emits the dynamic method.
        w.AccessPrivateMethod();
    }
}

/* This code example produces the following output:

Hello, World!
MethodAccessException was thrown when the delegate was invoked.
MethodAccessException was thrown when the delegate was invoked.
Worker.PrivateMethod()
MethodAccessException was thrown when the delegate was compiled.
 */
Imports System.Reflection.Emit
Imports System.Reflection
Imports System.Security
Imports System.Security.Permissions
Imports System.Security.Policy
Imports System.Collections
Imports System.Diagnostics

' This code example works properly only if it is run from a fully 
' trusted location, such as your local computer.

' Delegates used to execute the dynamic methods.
'
Public Delegate Sub Test(ByVal w As Worker)
Public Delegate Sub Test1()
Public Delegate Function Test2(ByVal instance As String) As Char

' The Worker class must inherit MarshalByRefObject so that its public 
' methods can be invoked across application domain boundaries.
'
Public Class Worker
    Inherits MarshalByRefObject

    Private Sub PrivateMethod()
        Console.WriteLine("Worker.PrivateMethod()")
    End Sub

    Public Sub SimpleEmitDemo()

        Dim meth As DynamicMethod = new DynamicMethod("", Nothing, Nothing)
        Dim il As ILGenerator = meth.GetILGenerator()
        il.EmitWriteLine("Hello, World!")
        il.Emit(OpCodes.Ret)

        Dim t1 As Test1 = CType(meth.CreateDelegate(GetType(Test1)), Test1)
        t1()
    End Sub

    ' This overload of AccessPrivateMethod emits a dynamic method and
    ' specifies whether to skip JIT visiblity checks. It creates a 
    ' delegate for the method and invokes the delegate. The dynamic 
    ' method calls a private method of the Worker class.
    Overloads Public Sub AccessPrivateMethod( _
                       ByVal restrictedSkipVisibility As Boolean)

        ' Create an unnamed dynamic method that has no return type,
        ' takes one parameter of type Worker, and optionally skips JIT
        ' visiblity checks.
        Dim meth As New DynamicMethod("", _
                                      Nothing, _
                                      New Type() {GetType(Worker)}, _
                                      restrictedSkipVisibility)

        ' Get a MethodInfo for the private method.
        Dim pvtMeth As MethodInfo = GetType(Worker).GetMethod( _
            "PrivateMethod", _
            BindingFlags.NonPublic Or BindingFlags.Instance)

        ' Get an ILGenerator and emit a body for the dynamic method.
        Dim il As ILGenerator = meth.GetILGenerator()

        ' Load the first argument, which is the target instance, onto the
        ' execution stack, call the private method, and return.
        il.Emit(OpCodes.Ldarg_0)
        il.EmitCall(OpCodes.Call, pvtMeth, Nothing)
        il.Emit(OpCodes.Ret)

        ' Create a delegate that represents the dynamic method, and 
        ' invoke it. 
        Try
            Dim t As Test = CType(meth.CreateDelegate(GetType(Test)), Test)
            Try
                t(Me)
            Catch ex As Exception
                Console.WriteLine("{0} was thrown when the delegate was invoked.", _
                    ex.GetType().Name)
            End Try
        Catch ex As Exception
            Console.WriteLine("{0} was thrown when the delegate was compiled.", _
                ex.GetType().Name)
        End Try

    End Sub


    ' This overload of AccessPrivateMethod emits a dynamic method that takes
    ' a string and returns the first character, using a private field of the 
    ' String class. The dynamic method skips JIT visiblity checks.
    Overloads Public Sub AccessPrivateMethod()

        Dim meth As New DynamicMethod("", _
                                      GetType(Char), _
                                      New Type() {GetType(String)}, _
                                      True)

        ' Get a MethodInfo for the 'get' accessor of the private property.
        Dim pi As PropertyInfo = GetType(String).GetProperty( _
            "FirstChar", _
            BindingFlags.NonPublic Or BindingFlags.Instance)
        Dim pvtMeth As MethodInfo = pi.GetGetMethod(True)

        ' Get an ILGenerator and emit a body for the dynamic method.
        Dim il As ILGenerator = meth.GetILGenerator()

        ' Load the first argument, which is the target string, onto the
        ' execution stack, call the 'get' accessor to put the result onto 
        ' the execution stack, and return.
        il.Emit(OpCodes.Ldarg_0)
        il.EmitCall(OpCodes.Call, pvtMeth, Nothing)
        il.Emit(OpCodes.Ret)

        ' Create a delegate that represents the dynamic method, and 
        ' invoke it. 
        Try
            Dim t As Test2 = CType(meth.CreateDelegate(GetType(Test2)), Test2)
            Dim first As Char = t("Hello, World!")
            Console.WriteLine("{0} is the first character.", first)
        Catch ex As Exception
            Console.WriteLine("{0} was thrown when the delegate was compiled.", _
                ex.GetType().Name)
        End Try

    End Sub
End Class

Friend Class Example

    ' The entry point for the code example.
    Shared Sub Main()

        ' Get the display name of the executing assembly, to use when
        ' creating objects to run code in application domains.
        Dim asmName As String = GetType(Worker).Assembly.FullName

        ' Create the permission set to grant to other assemblies. In this
        ' case they are the permissions found in the Internet zone.
        Dim ev As New Evidence()
        ev.AddHostEvidence(new Zone(SecurityZone.Internet))
        Dim pset As New NamedPermissionSet("Internet", SecurityManager.GetStandardSandbox(ev))

        ' For simplicity, set up the application domain to use the 
        ' current path as the application folder, so the same executable
        ' can be used in both trusted and untrusted scenarios. Normally
        ' you would not do this with real untrusted code.
        Dim adSetup As New AppDomainSetup()
        adSetup.ApplicationBase = "."

        ' Create an application domain in which all code that executes is 
        ' granted the permissions of an application run from the Internet.
        Dim ad As AppDomain = AppDomain.CreateDomain("Sandbox", ev, adSetup, pset, Nothing)

        ' Create an instance of the Worker class in the partially trusted 
        ' domain. Note: If you build this code example in Visual Studio, 
        ' you must change the name of the class to include the default 
        ' namespace, which is the project name. For example, if the project
        ' is "AnonymouslyHosted", the class is "AnonymouslyHosted.Worker".
        Dim w As Worker = _
            CType(ad.CreateInstanceAndUnwrap(asmName, "Worker"), Worker)

        ' Emit a simple dynamic method that prints "Hello, World!"
        w.SimpleEmitDemo()

        ' Emit and invoke a dynamic method that calls a private method
        ' of Worker, with JIT visibility checks enforced. The call fails 
        ' when the delegate is invoked.
        w.AccessPrivateMethod(False)

        ' Emit and invoke a dynamic method that calls a private method
        ' of Worker, skipping JIT visibility checks. The call fails when
        ' the method is compiled.
        w.AccessPrivateMethod(True)


        ' Unload the application domain. Add RestrictedMemberAccess to the
        ' grant set, and use it to create an application domain in which
        ' partially trusted code can call private members, as long as the 
        ' trust level of those members is equal to or lower than the trust 
        ' level of the partially trusted code. 
        AppDomain.Unload(ad)
        pset.SetPermission( _
            New ReflectionPermission( _
                ReflectionPermissionFlag.RestrictedMemberAccess))
        ad = AppDomain.CreateDomain("Sandbox2", ev, adSetup, pset, Nothing)

        ' Create an instance of the Worker class in the partially trusted 
        ' domain. 
        w = CType(ad.CreateInstanceAndUnwrap(asmName, "Worker"), Worker)

        ' Again, emit and invoke a dynamic method that calls a private method
        ' of Worker, skipping JIT visibility checks. This time compilation 
        ' succeeds because of the grant for RestrictedMemberAccess.
        w.AccessPrivateMethod(True)

        ' Finally, emit and invoke a dynamic method that calls an internal 
        ' method of the String class. The call fails, because the trust level
        ' of the assembly that contains String is higher than the trust level
        ' of the assembly that emits the dynamic method.
        w.AccessPrivateMethod()

    End Sub
End Class

' This code example produces the following output:
'
'Hello, World!
'MethodAccessException was thrown when the delegate was invoked.
'MethodAccessException was thrown when the delegate was invoked.
'Worker.PrivateMethod()
'MethodAccessException was thrown when the delegate was compiled.
' 

編譯程式碼

  • 如果您在 Visual Studio 中建置此程式碼範例,則當您將它傳遞給 CreateInstanceAndUnwrap 方法時,必須變更類別名稱以包含命名空間。 命名空間是專案的預設名稱。 例如,如果專案是 "PartialTrust",則類別名稱必須是 "PartialTrust.Worker"。

另請參閱