Frage

Ich habe ein Code-Snippet, das ein Skript mit der Skript-Engine kompiliert, und ich bin die Montage als Byte-Array zurück.

Jetzt möchte ich das laden Assembly In einem Sandkasten habe ich das: Ich habe:

Assembly _dynamicAssembly;
ScriptEngine _engine;
Session _session;

public string Execute(string code)
{
    // Setup sandbox
    var e = new Evidence();
    e.AddHostEvidence(new Zone(SecurityZone.Internet));
    var ps = SecurityManager.GetStandardSandbox(e);
    var setup = new AppDomainSetup 
                         { ApplicationBase = Environment.CurrentDirectory };
    var domain = 
        AppDomain.CreateDomain("Sandbox", 
                               AppDomain.CurrentDomain.Evidence, setup, ps);
    AppDomain.CurrentDomain.AssemblyResolve += DomainAssemblyResolve;

    // Process code
    var submission = _engine.CompileSubmission<object>(code, _session);
    submission.Compilation.Emit(memoryStream);
    var assembly = memoryStream.ToArray();

    _dynamicAssembly = Assembly.Load(assembly);

    var loaded = domain.Load(assembly);

    // Rest of the code...
}

Dies ist der Event -Handler für AssemblyResolve:

Assembly DomainAssemblyResolve(object sender, ResolveEventArgs args)
{
    return _dynamicAssembly;
}

Das bedeutet, dass, wenn ich es tue domain.Load(assembly) Ich werde die _dynamicassembly bekommen, wenn ich dieses Ereignis nicht abonniere und diese zurückgibt Assembly, Ich bekomme ein FileNotFoundException.

Das obige kompiliert und läuft, aber das Problem ist, dass der Code, der in der Domänenvermittlung ausgeführt wird, nicht tatsächlich in der Sandbox ausgeführt wird. Wenn ich die Einreichungsmethode bekomme und die Fabrik darin aufrufen und diese zurückgeben AppDomain.CurrentDomain.FriendlyName Das Ergebnis ist: MyRoslynApplication.vshost.exe welches ist nicht Der Sandkasten AppDomain

Laden ich meine byte[]-Allembly falsch?

War es hilfreich?

Lösung

Wenn Sie einen Typ laden möchten, der in der Sandbox ausgeführt wird und aus Ihrer Haupt -Appdomain darauf zugreift, müssen Sie eine Methode wie verwenden CreateInstance Fromandunwrap. Der Typ muss ein MarshalbyrefObject sein, damit er einen transparenten Proxy in der aufrufenden AppDomain für den Zugriff erstellen kann.

Wenn die Haupt -Appdomain die Baugruppe auflöst, wird sie in die Haupt -Appdomain (sowie die Sandbox Appdomain) geladen, damit Sie zwei Kopien geladen haben. Ihre Haupt -Appdomain muss immer über Proxys von der Sandbox isoliert bleiben, sodass nur MarshalbyrefObject und serialisierbare Objekte zugegriffen werden können. Beachten Sie, dass der Typ, auf den Sie sich verweisen, auch in der Baugruppe, die Sie in die Sandkasten laden möchten, nicht definiert werden können. Sie möchten Schnittstellen und möglicherweise serialisierbare Typen in einer dritten gemeinsamen Baugruppe definieren, die dann sowohl in die Haupt- als auch in Sandbox -Appdomains geladen wird.


Ich habe ein paar zusätzliche Graben gemacht und es sieht so aus, als ob alle Methoden zum Laden einer Baugruppe in eine andere Appdomain und das Erstellen eines Proxy erforderlich sind, um einen Montage -Namen zu lösen. Ich bin mir nicht sicher, ob es möglich ist, in diesem Fall über ein Byte [] zu laden. Möglicherweise müssen Sie die Baugruppe auf Festplatten speichern und laden. Ich werde ein bisschen mehr graben.


Ich denke, Sie können das tun (das ist ungetestet, aber es scheint plausibel).

Diese müssten sich in einer "Schnittstelle" befinden, die sowohl für Ihre Haupt -App als auch in der Sandbox zugänglich ist (ich werde sie als Dienste bezeichnen.dll):

public interface IMyService
{
    //.... service-specific methods you'll be using
}

public interface IStubLoader
{
    Object CreateInstanceFromAndUnwrap(byte[] assemblyBytes, string typeName);
}

Als nächstes kommt eine Klasse in einem Stublader.dll. Sie werden diese Baugruppe nicht direkt verweisen. Hier nennen Sie die erste AppDomain.CreateInstanceFromandunWrap, die dies als Montage -Name und Stubloader als Typname bereitstellt.

public sealed class StubLoader: MarshalByRefObject, IStubLoader
    {
        public object CreateInstanceFromAndUnwrap(byte[] assemblyBytes, string typeName)
        {
            var assembly = Assembly.Load(assemblyBytes);
            return assembly.CreateInstance(typeName);
        }
    }

Um es jetzt von Ihrer Haupt -Appdomain zu verwenden, tun Sie dies:

//Create transparent proxy for the stub loader, which will live in the sandbox
var stubLoader = (IStubLoader)sandboxDomain.CreateInstanceFromAndUnwrap("Stubloader.dll", "StubLoader");

//Have the stub loader marshal a proxy to a dynamically loaded assembly (via byte[]) where MyService is the type name implementing MarshalByRefObject and IMyService
var myService = (IMyService)stubLoader.CreateInstanceFromAndUnwrap(assemblyBytes, "MyService");

Leider sind Appdomains nicht einfach zu bedienen. Dies liegt daran, dass sie ein hohes Maß an Isolierung darstellen und daher ein Verstehen erfordern, um die Nutzung über Appdomain -Grenzen hinweg zu ermöglichen.


Als Reaktion darauf, wie Sie eine nicht-serialisierbare und nicht-marshalbyrefObject-Klasse marschallieren können, finden Sie hier ein grobes Beispiel für das, was sich in der gemeinsamen Schnittstelle befinden könnte:

public interface ISessionWrapper
{
    void DoSomethingWithSession();
}

public sealed class SessionWrapper : MarshalByRefObject, ISessionWrapper
{
    private readonly Session _session;

    public SessionWrapper(Session session)
    {
        _session = session;
    }

    public void DoSomethingWithSession()
    {
        //Do something with the wrapped session...
        //This executes inside the sandbox, even though it can be called (via proxy) from outside the sandbox
    }
}

Überall, wo Ihr ursprünglicher Service für die Arbeit mit Sitzung benötigt wird, kann er stattdessen IsSessionWrapper übergeben, dessen Anrufe hinter den Kulissen gesammelt werden, sodass alle tatsächlichen Code in der Sandbox in einer realen Sitzungsinstanz ausgeführt werden, die in der Sandbox lebt.

Andere Tipps

Wahrscheinlich könnte dies auch helfen:

https://docs.microsoft.com/en-us/dotnet/framework/misc/how-to-run-partial trusted-code-in-a-sandbox

Außerdem musste ich den erstellten Assembly -Dateistrom auf der Festplatte bestehen, um die Sandbox zum Laufen zu bringen. Ich kämpfe immer noch mit einer starken Benennung und Unit -Tests der Lösung (es gibt über 16 Projekte). Ich werde mich jedoch mit der Arbeitskopie bei Ihnen melden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top