I have a unit test that basically does the following:
Creates an app domain using minimum priviledges. The MarshalByRefObject that is living in the app domain, loads another assembly to execute. This new assembly basically takes in a data object defined in a separate assembly, and returns a new data object of that type.
All this works fine in debug mode, or when running w/out code coverage. The Sandbox assembly is signed.
The exception that gets thrown is this:
Test method TestProject1.UnitTest1.TestMethod1 threw exception:
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Security.VerificationException: Operation could destabilize the runtime.
ClassLibrary3.Bar..ctor()
ClassLibrary2.Foo.TestMethod(Bar testBar)
System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
ClassLibrary1.RemoteSandBox.Execute(String assemblyPath, String scriptType, String method, Object[] parameters)
ClassLibrary1.RemoteSandBox.Execute(String assemblyPath, String scriptType, String method, Object[] parameters)
ClassLibrary1.SandBox.Execute(String assemblyPath, String scriptType, String method, Object[] parameters) in c:\users\la22426\documents\visual studio 2010\Projects\TestProject1\ClassLibrary1\Sandbox.cs: line 43
TestProject1.UnitTest1.TestMethod1() in c:\users\la22426\documents\visual studio 2010\Projects\TestProject1\TestProject1\UnitTest1.cs: line 21
Unit Test code:
[TestClass] public class UnitTest1 { [TestMethod] public void TestMethod1() { using (SandBox sandbox = new SandBox()) { string assemblyLocation = Path.Combine(Environment.CurrentDirectory, @"..\..\..\ClassLibrary2\bin\Debug\ClassLibrary2.dll"); object result = sandbox.Execute(assemblyLocation, "ClassLibrary2.Foo", "TestMethod", new Bar() { X = "test" }); Assert.IsNotNull(result); } } }
Data Object code:
namespace ClassLibrary3 { [Serializable] public class Bar { public Bar() { } public string X { get; set; } } }
Assembly to execute code:
namespace ClassLibrary2 { public class Foo { public Bar TestMethod(Bar testBar) { return new Bar() { X = testBar.X }; } } }
Sandbox code:
namespace ClassLibrary1 { public class SandBox : IDisposable { AppDomain Domain { get; set; } RemoteSandBox RemoteSandBox { get; set; } public SandBox() { var setup = new AppDomainSetup() { ApplicationBase = AppDomain.CurrentDomain.BaseDirectory, ApplicationName = Guid.NewGuid().ToString(), DisallowBindingRedirects = true, DisallowCodeDownload = true, DisallowPublisherPolicy = true, //DisallowApplicationBaseProbing = true, }; var permissions = new PermissionSet(PermissionState.None); permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution)); permissions.AddPermission(new ReflectionPermission(PermissionState.Unrestricted)); this.Domain = AppDomain.CreateDomain(setup.ApplicationName, null, setup, permissions, typeof(RemoteSandBox).Assembly.Evidence.GetHostEvidence<StrongName>()); this.RemoteSandBox = (RemoteSandBox)Activator.CreateInstanceFrom(this.Domain, typeof(RemoteSandBox).Assembly.ManifestModule.FullyQualifiedName, typeof(RemoteSandBox).FullName).Unwrap(); } public object Execute(string assemblyPath, string scriptType, string method, params object[] parameters) { return this.RemoteSandBox.Execute(assemblyPath, scriptType, method, parameters); } public void Dispose() { if (this.Domain != null) { AppDomain.Unload(this.Domain); } } } class RemoteSandBox : MarshalByRefObject { public RemoteSandBox() { } public object Execute(string assemblyPath, string scriptType, string method, params object[] parameters) { //we need some file io permissions to load the assembly new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.PathDiscovery, assemblyPath).Assert(); Assembly assembly; try { assembly = Assembly.LoadFile(assemblyPath); } finally { CodeAccessPermission.RevertAssert(); } Type type = assembly.GetType(scriptType, true); MethodInfo methodInfo = type.GetMethod(method); object instance = (methodInfo.IsStatic) ? null : Activator.CreateInstance(type); object returnVal = null; returnVal = methodInfo.Invoke(instance, parameters); return returnVal; } } }