具有受限AppDomain的IronPython

时间:2014-11-19 21:59:34

标签: c# ironpython sandbox appdomain

当我尝试在具有受限权限的AppDomain中运行IronPython脚本引擎时,我遇到了启动时间过长的问题。有人可以提供一个如何以高效的方式执行此操作的规范示例吗?

No AppDomain no standard library
Time taken: 36.1022ms

No AppDomain with standard library
Time taken: 37.8556ms

我看到它在某处提到创建AppDomain实例很昂贵。创建一个受限制的AppDomain并重用它是最佳做法吗?

[assembly: AllowPartiallyTrustedCallers]

public class ScriptEvaluator : MarshalByRefObject
{
    public ScriptEngine ScriptEngine { get; set; }
    public String PythonStandardLibaryPath { get; set; }
    public String PythonApplicationCodePath { get; set; }

    public ScriptEvaluator()
    {
        PythonStandardLibaryPath = Path.GetFullPath(@"..\..\..\MyProject\standard_library");
        PythonApplicationCodePath = Path.GetFullPath(@"..\..\..\MyProject\python_code");
    }

    public ScriptEvaluator InstantiateInAppDomain()
    {
        /* create app domain setup */
        var appDomainSetup = new AppDomainSetup { ApplicationBase = Environment.CurrentDirectory };
        //appDomainSetup.ApplicationBase = Path.GetDirectoryName(Environment.CurrentDirectory);
        //appDomainSetup.ApplicationBase = Environment.CurrentDirectory;
        //appDomainSetup.DisallowBindingRedirects = false;
        //appDomainSetup.DisallowCodeDownload = true;
        //appDomainSetup.ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;

        /* assign permissions */
        var permissionSet = new PermissionSet(PermissionState.None);
        permissionSet.AddPermission(new ReflectionPermission(PermissionState.Unrestricted));
        permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
        permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, PythonStandardLibaryPath));
        permissionSet.AddPermission(new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, PythonApplicationCodePath));

        if (Debugger.IsAttached)
        {
            permissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode));
        }

        /* create a script evaluator instance in the app domain and return a reference */
        var appDomain = AppDomain.CreateDomain("Sandbox", null, appDomainSetup, permissionSet);
        var scriptEvaluator = (ScriptEvaluator)appDomain.CreateInstanceAndUnwrap("MyProject", typeof(ScriptEvaluator).FullName);
        scriptEvaluator.CreateScriptEngine();

        return scriptEvaluator;
    }

    public ScriptEngine CreateScriptEngine()
    {
        /* create the iron IronPython engine */
        var options = new Dictionary<string, object> { { "Debug", Debugger.IsAttached } };
        ScriptEngine = Python.CreateEngine(options);

        /* add library directories to the search paths */
        var searchPaths = ScriptEngine.GetSearchPaths();
        searchPaths.Add(PythonStandardLibaryPath);
        searchPaths.Add(PythonApplicationCodePath);
        ScriptEngine.SetSearchPaths(searchPaths);

        return ScriptEngine;
    }
}

注意:我必须使用AllowPartiallyTrustedCallers来解决安全错误,我不确定这是否是一种理想的方法。

用法:

var scriptEvaluator = new ScriptEvaluator().InstantiateInAppDomain();
var scriptScope = scriptEvaluator.ScriptEngine.CreateScope();
script = @"from mymodule import *; a = 1 + 1; b = 2 + 2; c = a + b";

foreach (var number in Enumerable.Range(1, 10))
{
    Stopwatch stopwatch = Stopwatch.StartNew();
    scriptEvaluator.ScriptEngine.Execute(script, scriptScope);
    stopwatch.Stop(); Console.WriteLine("Time taken: {0}ms", stopwatch.Elapsed.TotalMilliseconds);
}

进行了一些分析,看起来第一次执行ScriptEngine.Execute比后续执行更昂贵。

// Time taken:     8.937ms -- InstantiateInAppDomain
// Time taken:  429.9291ms -- CreateScriptEngine
// Time taken:    9.1289ms -- CreateScope
// Time taken: 2080.1795ms -- ScriptEngine.Execute first
// Time taken:    5.2469ms -- ScriptEngine.Execute second
// Time taken:    7.9255ms -- ScriptEngine.Execute third
// Time taken:    3.1206ms -- ScriptEngine.Execute fourth
// Time taken:    3.1316ms -- ScriptEngine.Execute fifth
// Time taken:    3.0643ms -- ScriptEngine.Execute sixth

是否有人知道缺少哪些权限才能在受限制的AppDomain中导入os模块?添加我能找到的每个权限都不起作用。

0 个答案:

没有答案