Procedura dettagliata: Creazione di codice in scenari di attendibilità parziale

La reflection emit usa le stesse API in scenari di attendibilità sia parziale che completa, ma alcune funzionalità richiedono autorizzazioni speciali nel codice parzialmente attendibile. Inoltre, la reflection emit include una funzionalità, i metodi dinamici ospitati in modo anonimo, progettata per l'uso in situazioni di attendibilità parziale da parte di assembly trasparenti per la sicurezza.

Nota

Prima di .NET Framework 3.5, la creazione di codice richiedeva ReflectionPermission con il flag ReflectionPermissionFlag.ReflectionEmit. Questa autorizzazione è inclusa per impostazione predefinita nei set di autorizzazioni denominati FullTrust e Intranet, ma non nel set di autorizzazioni Internet. Di conseguenza, una libreria può essere usata con attendibilità parziale solo se in essa era presente l'attributo SecurityCriticalAttribute e veniva eseguito un metodo Assert per ReflectionEmit. Tali librerie richiedono un'attenta revisione della sicurezza perché eventuali errori nel codice potrebbe produrre delle vulnerabilità. .NET Framework 3.5 consente di generare codice in scenari con attendibilità parziale senza creare alcuna richiesta di sicurezza, poiché la generazione di codice non è implicitamente un'operazione con privilegi. Ovvero, il codice generato non dispone di ulteriori autorizzazioni rispetto all'assembly che lo genera. Questo consente alle librerie che generano il codice di essere trasparenti per la sicurezza ed elimina la necessità di asserire ReflectionEmit, quindi la scrittura di una libreria protetta non richiede una revisione completa della sicurezza.

Vengono illustrate le attività seguenti:

Per altre informazioni sulla generazione di codice in scenari di attendibilità parziale, vedere la sezione relativa ai problemi di sicurezza nella reflection emit.

Per un elenco completo del codice riportato in queste procedure, vedere la sezione degli esempi alla fine di questa procedura dettagliata.

Impostazione di percorsi parzialmente attendibili

Le due procedure seguenti illustrano come impostare i percorsi da cui è possibile testare il codice con attendibilità parziale.

  • La prima procedura spiega come creare un dominio dell'applicazione sandbox in cui vengono concesse autorizzazioni Internet al codice.

  • La seconda procedura illustra come aggiungere ReflectionPermission con il flag ReflectionPermissionFlag.RestrictedMemberAccess a un dominio dell'applicazione parzialmente attendibile, per consentire l'accesso ai dati privati negli assembly con attendibilità uguale o inferiore.

Creazione di domini dell'applicazione sandbox

Per creare un dominio applicazione in cui gli assembly sono eseguiti con attendibilità parziale, è necessario specificare il set di autorizzazioni da concedere agli assembly usando l'overload del metodo AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) per creare il dominio dell'applicazione. Il modo più semplice per specificare il set di concessioni è recuperare un set di autorizzazioni denominato dai criteri di sicurezza.

Nella procedura seguente viene creato un dominio dell'applicazione sandbox che esegue il codice con attendibilità parziale, per testare gli scenari in cui il codice generato può accedere solo ai membri pubblici dei tipi pubblici. Una procedura successiva illustra come aggiungere RestrictedMemberAccess, per testare scenari in cui il codice generato può accedere a tipi e membri non pubblici negli assembly a cui vengono concesse autorizzazioni uguali o inferiori.

Per creare un dominio dell'applicazione con attendibilità parziale

  1. Creare un set di autorizzazioni da concedere agli assembly nel dominio dell'applicazione sandbox. In questo caso viene usato il set di autorizzazioni dell'area Internet.

    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. Creare un oggetto AppDomainSetup per inizializzare il dominio dell'applicazione con un percorso dell'applicazione.

    Importante

    Per semplicità, questo esempio di codice usa la cartella corrente. Per eseguire codice realmente proveniente da Internet, usare una cartella separata per il codice non attendibile, come descritto nella procedura relativa all'esecuzione di codice parzialmente attendibile in un oggetto sandbox.

    AppDomainSetup adSetup = new AppDomainSetup();
    adSetup.ApplicationBase = ".";
    
    Dim adSetup As New AppDomainSetup()
    adSetup.ApplicationBase = "."
    
  3. Creare il dominio dell'applicazione, specificando le informazioni di configurazione del dominio dell'applicazione e il set di concessioni per tutti gli assembly eseguiti nel dominio dell'applicazione.

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

    L'ultimo parametro dell'overload del metodo AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) consente di specificare un set di assembly a cui deve essere concessa l'attendibilità totale, anziché il set di concessioni del dominio dell'applicazione. Non è necessario specificare gli assembly .NET Framework usati dall'applicazione, perché si trovano nella Global Assembly Cache. Gli assembly nella Global Assembly Cache sono sempre completamente attendibili. È possibile usare questo parametro per specificare assembly con nome sicuro che non sono presenti nella Global Assembly Cache.

Aggiunta di RestrictedMemberAccess ai domini sandbox

Le applicazioni host possono consentire ai metodi dinamici ospitati in modo anonimo di accedere ai dati privati negli assembly con livelli di attendibilità uguali o inferiori a quelli dell'assembly che genera il codice. Per abilitare la possibilità limitata di ignorare i controlli di visibilità just-in-time (JIT), l'applicazione host aggiunge un oggetto ReflectionPermission con il flag ReflectionPermissionFlag.RestrictedMemberAccess (RMA) al set di concessioni.

Ad esempio, un host può concedere alle applicazioni Internet autorizzazioni Internet più RMA, in modo tale che un'applicazione Internet sia in grado di generare codice che accede ai dati privati nei propri assembly. Poiché l'accesso è limitato agli assembly con attendibilità uguale o minore, un'applicazione Internet non può accedere a membri di assembly completamente attendibili, ad esempio gli assembly .NET Framework.

Nota

Per evitare l'elevazione dei privilegi, le informazioni sullo stack per l'assembly di creazione vengono incluse quando si creano metodi dinamici ospitati in modo anonimo. Quando il metodo viene richiamato, vengono controllate le informazioni sullo stack. Di conseguenza, un metodo dinamico ospitato in modo anonimo richiamato da codice completamente attendibile è comunque limitato al livello di attendibilità dell'assembly di creazione.

Per creare un dominio dell'applicazione con attendibilità parziale più RMA

  1. Creare un nuovo oggetto ReflectionPermission con il flag RestrictedMemberAccess (RMA) e usare il metodo PermissionSet.SetPermission per aggiungere l'autorizzazione al set di concessioni.

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

    Il metodo AddPermission aggiunge l'autorizzazione al set di concessioni, se non è già inclusa. Se l'autorizzazione è già inclusa nel set di concessioni, i flag specificati vengono aggiunti all'autorizzazione esistente.

    Nota

    RMA è una funzionalità dei metodi dinamici ospitati in modo anonimo. Quando i metodi dinamici comuni ignorano i controlli di visibilità JIT, il codice generato richiede l'attendibilità totale.

  2. Creare il dominio dell'applicazione, specificando le informazioni di configurazione del dominio dell'applicazione e il set di concessioni.

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

Esecuzione di codice nei domini dell'applicazione sandbox

La procedura seguente spiega come definire una classe usando metodi che possono essere eseguiti in un dominio dell'applicazione, come creare un'istanza della classe nel dominio e come eseguire i relativi metodi.

Per definire ed eseguire un metodo in un dominio dell'applicazione

  1. Definire una classe che deriva da MarshalByRefObject. Ciò consente di creare istanze della classe in altri domini dell'applicazione e di effettuare chiamate al metodo tra i limiti del dominio dell'applicazione. La classe di questo esempio è denominata Worker.

    public class Worker : MarshalByRefObject
    {
    
    Public Class Worker
        Inherits MarshalByRefObject
    
  2. Definire un metodo pubblico che contenga il codice da eseguire. In questo esempio, il codice genera un metodo dinamico semplice, crea un delegato per eseguire il metodo e richiama il delegato.

    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. Nel programma principale ottenere il nome visualizzato dell'assembly. Questo nome viene usato quando si creano istanze della classe Worker nel dominio dell'applicazione sandbox.

    String asmName = typeof(Worker).Assembly.FullName;
    
    Dim asmName As String = GetType(Worker).Assembly.FullName
    
  4. Nel programma principale creare un dominio dell'applicazione sandbox, come descritto nella prima procedura in questa procedura dettagliata. Non è necessario aggiungere autorizzazioni al set di autorizzazioni Internet, poiché il metodo SimpleEmitDemo usa solo metodi pubblici.

  5. Nel programma principale creare un'istanza della classe Worker nel dominio dell'applicazione sandbox.

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

    Il metodo CreateInstanceAndUnwrap crea l'oggetto nel dominio dell'applicazione di destinazione e restituisce un proxy che può essere usato per chiamare le proprietà e metodi dell'oggetto.

    Nota

    Se questo codice viene utilizzato in Visual Studio, è necessario modificare il nome della classe per includere lo spazio dei nomi. Per impostazione predefinita, lo spazio dei nomi è il nome del progetto. Ad esempio, se il progetto è "PartialTrust", il nome della classe deve essere "PartialTrust.Worker".

  6. Aggiungere il codice per chiamare il metodo SimpleEmitDemo . La chiamata viene eseguita attraverso il limite del dominio dell'applicazione e il codice viene eseguito nel dominio dell'applicazione in modalità sandbox.

    w.SimpleEmitDemo();
    
    w.SimpleEmitDemo()
    

Uso dei metodi dinamici ospitati in modo anonimo

I metodi dinamici ospitati in modo anonimo sono associati a un assembly trasparente messo a disposizione dal sistema. Di conseguenza, il codice che contengono è trasparente. I metodi dinamici comuni, d'altra parte, devono essere associati a un modulo esistente, specificato direttamente o derivato da un tipo associato, e ricevono il livello di sicurezza da tale modulo.

Nota

L'unico modo di associare un metodo dinamico all'assembly che offre l'hosting anonimo è usare i costruttori descritti nella procedura seguente. Non è possibile specificare in modo esplicito un modulo nell'assembly di hosting anonimo.

I metodi dinamici comuni hanno accesso ai membri interni del modulo a cui sono associati o ai membri privati del tipo a cui sono associati. Poiché i metodi dinamici ospitati in modo anonimo sono isolati dall'altro codice, non hanno accesso ai dati privati. Usano tuttavia una possibilità limitata per ignorare i controlli di visibilità JIT in modo da ottenere l'accesso ai dati privati. Tale possibilità è limitata agli assembly con livelli di attendibilità uguali o inferiori a quello dell'assembly che genera il codice.

Per evitare l'elevazione dei privilegi, le informazioni sullo stack per l'assembly di creazione vengono incluse quando si creano metodi dinamici ospitati in modo anonimo. Quando il metodo viene richiamato, vengono controllate le informazioni sullo stack. Un metodo dinamico ospitato in modo anonimo richiamato da un codice completamente attendibile è comunque limitato al livello di attendibilità dell'assembly in cui è stato creato.

Per usare i metodi dinamici ospitati in modo anonimo

  • Creare un metodo dinamico ospitato in modo anonimo usando un costruttore che non specifica un modulo o un tipo associato.

    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)
    

    Se un metodo dinamico ospitato in modo anonimo usa solo tipi e metodi pubblici, non richiede l'accesso limitato al membro e non è necessario ignorare i controlli di visibilità JIT.

    Non sono richieste autorizzazioni speciali per generare un metodo dinamico, ma per il codice generato sono necessarie le autorizzazioni obbligatorie per i tipi e i metodi usati. Ad esempio, se il codice generato chiama un metodo che accede a un file, richiede FileIOPermission. Se il livello di attendibilità non include tale autorizzazione, viene generata un'eccezione di sicurezza quando viene eseguito il codice generato. Il codice riportato di seguito genera un metodo dinamico che usa solo il metodo Console.WriteLine. Di conseguenza, il codice può essere eseguito da percorsi parzialmente attendibili.

  • In alternativa, creare un metodo dinamico ospitato in modo anonimo con la possibilità limitata di ignorare i controlli di visibilità JIT, usando il costruttore DynamicMethod(String, Type, Type[], Boolean) e specificando true per il parametro restrictedSkipVisibility.

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

    La limitazione consiste nel fatto che il metodo dinamico ospitato in modo anonimo può accedere ai dati privati solo negli assembly con livelli di attendibilità uguali o inferiori a quello dell'assembly di creazione. Ad esempio, se il metodo dinamico è in esecuzione con attendibilità Internet, può accedere ai dati privati in altri assembly in esecuzione con attendibilità Internet, ma non può accedere ai dati privati degli assembly .NET Framework. Gli assembly .NET Framework sono installati nella Global Assembly Cache e sono sempre completamente attendibili.

    I metodi dinamici ospitati in modo anonimo possono usare questa possibilità limitata di ignorare i controlli di visibilità JIT solo se l'applicazione host concede ReflectionPermission con il flag ReflectionPermissionFlag.RestrictedMemberAccess. La richiesta di questa autorizzazione viene effettuata quando viene richiamato il metodo.

    Nota

    Le informazioni sullo stack di chiamate per l'assembly di creazione vengono incluse quando viene costruito il metodo dinamico. Di conseguenza, la richiesta viene effettuata facendo riferimento alle autorizzazioni dell'assembly di creazione anziché a quelle dell'assembly che richiama il metodo. Ciò impedisce che il codice generato venga eseguito con autorizzazioni elevate.

    L'esempio di codice completo alla fine di questa procedura dettagliata illustra l'uso e le limitazioni dell'accesso limitato al membro. La relativa classe Worker include un metodo in grado di creare metodi dinamici ospitati in modo anonimo con o senza la possibilità limitata di ignorare i controlli di visibilità e l'esempio illustra il risultato dell'esecuzione di questo metodo nei domini dell'applicazione con diversi livelli di attendibilità.

    Nota

    La possibilità limitata di ignorare i controlli di visibilità è una funzionalità di metodi dinamici ospitati in modo anonimo. Quando i metodi dinamici comuni ignorano i controlli di visibilità JIT, deve essere concessa l'attendibilità totale.

Esempio

Descrizione

Nell'esempio di codice riportato di seguito viene illustrato l'uso del flag RestrictedMemberAccess per consentire ai metodi dinamici ospitati in modo anonimo di ignorare i controlli di visibilità JIT, ma solo quando il membro di destinazione è un livello uguale o inferiore di attendibilità rispetto all'assembly che genera il codice.

L'esempio definisce una Worker classe che può essere marshallata tra limiti di dominio dell'applicazione. La classe ha due overload del metodo AccessPrivateMethod che generano ed eseguono i metodi dinamici. Il primo overload genera un metodo dinamico che chiama il metodo privato PrivateMethod della classe Worker e può generare il metodo dinamico con o senza controlli di visibilità JIT. Il secondo overload genera un metodo dinamico che accede a una proprietà internal (proprietà Friend in Visual Basic) della classe String.

L'esempio usa un metodo helper per creare un set di concessioni limitato alle autorizzazioni Internet, quindi crea un dominio dell'applicazione usando l'overload del metodo AppDomain.CreateDomain(String, Evidence, AppDomainSetup, PermissionSet, StrongName[]) per specificare che tutto il codice eseguito nel dominio usa questo set di concessioni. Nell'esempio viene creata un'istanza della classe Worker nel dominio dell'applicazione e viene eseguito due volte il metodo AccessPrivateMethod.

  • La prima volta che il metodo AccessPrivateMethod viene eseguito, vengono applicati i controlli di visibilità JIT. Il metodo dinamico ha esito negativo quando viene richiamato, perché i controlli di visibilità JIT impediscono l'accesso al metodo privato.

  • La seconda volta che il metodo AccessPrivateMethod viene eseguito, i controlli di visibilità JIT vengono ignorati. Il metodo dinamico ha esito negativo quando viene compilato, poiché il set di concessioni Internet non concede autorizzazioni sufficienti per ignorare i controlli di visibilità.

Nell'esempio viene aggiunto ReflectionPermission con ReflectionPermissionFlag.RestrictedMemberAccess al set di concessioni. Viene quindi creato un secondo dominio, specificando che a tutto il codice eseguito nel dominio vengano concesse le autorizzazioni del nuovo set di concessioni. Viene creata un'istanza della classe Worker nel nuovo dominio dell'applicazione e vengono eseguiti entrambi gli overload del metodo AccessPrivateMethod.

  • Viene eseguito il primo overload del metodo AccessPrivateMethod e i controlli di visibilità JIT vengono ignorati. Il metodo dinamico viene compilato ed eseguito correttamente, poiché l'assembly che genera il codice è lo stesso assembly che contiene il metodo privato. Di conseguenza, i livelli di attendibilità sono uguali. Se l'applicazione che contiene la classe Worker ha diversi assembly, l'esito del processo sarà lo stesso per tutti gli assembly, poiché sono tutti allo stesso livello di attendibilità.

  • Viene eseguito il secondo overload del metodo AccessPrivateMethod e i controlli di visibilità JIT vengono di nuovo ignorati. Questa volta il metodo dinamico ha esito negativo quando viene compilato, perché tenta di accedere alla proprietà internalFirstChar della classe String. L'assembly che contiene la classe String è completamente attendibile. Si trova quindi a un livello di attendibilità superiore rispetto all'assembly che genera il codice.

Questo confronto spiega come ReflectionPermissionFlag.RestrictedMemberAccess consente al codice parzialmente attendibile di ignorare i controlli di visibilità per altro codice parzialmente attendibile senza compromettere la sicurezza del codice attendibile.

Codice

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.
' 

Compilazione del codice

  • Se si compila questo esempio di codice in Visual Studio, è necessario modificare il nome della classe in modo che includa lo spazio dei nomi quando si passa la classe al metodo CreateInstanceAndUnwrap. Per impostazione predefinita, lo spazio dei nomi è il nome del progetto. Ad esempio, se il progetto è "PartialTrust", il nome della classe deve essere "PartialTrust.Worker".

Vedi anche