C# Reflection: Replace a referenced assembly - c#

I am currently writing a framework for MutationTesting. The code is almost complete, but there is a tiny bit which (after spending half a day on it) I cannot figure out:
via reflection I would like to execute a method "TestMethod" which is inside the class "TestClass". The project in which "TestClass" is, references an essembly, lets call it "Proband.dll".
The "TestMethod" creates an object of some type inside the Proband.dll and executes a method on that object.
In order to clarify a little:
TestClass - is a class that contains unit tests.
TestMethod - is a single unit test.
Proband.dll - contains the method/class to test.
Before executing the TestMethod, I already successfully disassembled, mutated and reassembled the Proband.dll. So now I have a new "Proband.dll" which shall be taken by the TestClass instead!
The problem is that the TestClass is already in the middle of execution. I was thinking whether it is possible to create an AppDomain in which the new Proband.dll will be loaded and inside the fresh AppDomain, the TestMethod will be executed.
I have already created this AppDomain and successfully loaded the new Proband.dll into it, however, I do not know how to execute the TestMethod inside this new AppDomain. Also I do not know whether this is going to "replace" the old Proband.dll for the test method.
Here is my TestClass:
[TestClass()]
public class TestClass
{
[TestInitialize()]
public void MyTestInitialize()
{
// code to perform the mutation.
// From here, the "TestMethod" should be called with
// the new "Proband.dll".
}
[TestMethod()]
public void TestMethod()
{
// test code calling into Proband.dll
}
}
Does anyone have an idea of how this could be achieved? Or any clue or keyword?
Thanks,
Christian

This is probably overkill, but check out my answer:
Static Fields in AppDomain
You'll want to create the TestClass in the AppDomain that you've loaded the Proband.dll in, and use a MarshalByRef to keep the class in the AppDomain (so you can unload it later).
Here is more about what I did (not exact, as i'm changing it to match more what you need).
// Create Domain
_RemoteDomain = AppDomain.CreateDomain(_RemoteDomainName,
AppDomain.CurrentDomain.Evidence,
AppDomain.CurrentDomain.BaseDirectory,
AppDomain.CurrentDomain.BaseDirectory,
true);
// Load an Assembly Loader in the domain (mine was Builder)
// This loads the Builder which is in the current domain into the remote domain
_Builder = (Builder)_RemoteDomain.CreateInstanceAndUnwrap(
Assembly.GetExecutingAssembly().FullName, "<namespace>.Builder");
_Builder.Execute(pathToTestDll)
public class Builder : MarshalByRefObject
{
public void Execute(string pathToTestDll)
{
// I used this so the DLL could be deleted while
// the domain was still using the version that
// exists at this moment.
Assembly newAssembly = Assembly.Load(
System.IO.File.ReadAllBytes(pathToTestDll));
Type testClass = newAssembly.GetType("<namespace>.TestClass",
false, true);
if (testClass != null)
{
// Here is where you use reflection and/or an interface
// to execute your method(s).
}
}
}
This should provide you the solution you need.

Related

Does AssemblyLoadContext isolate static variables?

Announcement tells us:
Assembly unloadability is a new capability of AssemblyLoadContext. This new feature is largely transparent from an API perspective, exposed with just a few new APIs. It enables a loader context to be unloaded, releasing all memory for instantiated types, static fields and for the assembly itself. An application should be able to load and unload assemblies via this mechanism forever without experiencing a memory leak.
Also, this design notes has mentioning of "statics".
I have tried this straightforward test:
static void Main()
{
Proxy.X = 15;
var alc = new AssemblyLoadContext("MyTest", true);
var asm = alc.LoadFromAssemblyName(typeof(Program).Assembly.GetName());
var proxy = (Proxy)asm.CreateInstance(typeof(Proxy).FullName);
Console.WriteLine(proxy.Increment());
}
class Proxy
{
public static int X;
public int Increment() => ++X;
}
It outputs "16", which means that isolation doesn't work.
My goal is to unit-test class static members which can throw exceptions. Usual tests can affect each other's behavior by triggering type initializers, so I need to isolate them in the cheapest possible way. Test should run on .NET Core 3.0.
Is it right way to do it, and can AssemblyLoadContext help with it?
Yes, it does isolate static variables.
If we look at the newest design notes, we see this addition:
LoadFromAssemblyName
This method can be used to load an assembly into
a load context different from the load context of the currently
executing assembly. The assembly will be loaded into the load context
on which the method is called. If the context can't resolve the
assembly in its Load method the assembly loading will defer to the
Default load context. In such case it's possible the loaded assembly
is from the Default context even though the method was called on a
non-default context.
Calling this method directly on the AssemblyLoadContext.Default will
only load the assembly from the Default context. Depending on the
caller the Default may or may not be different from the load context
of the currently executing assembly.
This method does not "forcefully" load the assembly into the specified
context. It basically initiates a bind to the specified assembly name
on the specified context. That bind operation will go through the full
binding resolution logic which is free to resolve the assembly from
any context (in reality the most likely outcome is either the
specified context or the default context). This process is described
above.
To make sure a specified assembly is loaded into the specified load
context call AssemblyLoadContext.LoadFromAssemblyPath and specify the
path to the assembly file.
It's little bit frustrating, because now I need to determine the exact location of the assembly to load (there's no easy way to "clone" already loaded assemblies).
This code works (outputs "1"):
static void Main()
{
Proxy.X = 15;
var alc = new AssemblyLoadContext("MyTest", true);
var asm = alc.LoadFromAssemblyPath(typeof(Program).Assembly.Location);
var proxy = asm.CreateInstance(typeof(Proxy).FullName);
Console.WriteLine(proxy.GetType().GetMethod("Increment").Invoke(null, null));
}
class Proxy
{
public static int X;
public static int Increment() => ++X;
}
(Notice, now we can't cast to Proxy class, because it is different from the run-time class of proxy variable, even being the same class...)

Impossible to run test with TestCaseData generated from RhinoMocks stub

I am working with C# in Visual Studio 2015 Community, with NUnit3 and Rhino Mocks and attempting to write a test for a component of my system (it is NOT a unit test).
I have encountered a problem when trying to use a generated stub as the argument to a TestCaseData that is provided to a TestCaseSource. I get the following errors in the output window:
Test adapter sent back a result for an unknown test case. Ignoring result for 'MyTest(Castle.Proxies.IMyInterfaceProxy4c6c716794ef48818f41fd5012345ead)'.
Test adapter sent back a result for an unknown test case. Ignoring result for 'MyTest(Castle.Proxies.IMyInterfaceProxy4c6c716794ef48818f41fd5012345ead)'.
The test name appears in the VS2015 integrated test-runner when I rebuild the test project, but as soon I try to run it it becomes greyed out.
Here there is some sample code based on my test code:
using NUnit.Framework;
using Rhino.Mocks;
using System.Collections;
namespace FenixLib.Core.Tests
{
public interface IMyInterface
{
int Property { get; }
}
[TestFixture]
class TestMocks
{
[Test, TestCaseSource( "TestCases" )]
public void MyTest(IMyInterface what)
{
// Do stuff
}
public static IEnumerable TestCases()
{
yield return new TestCaseData ( CreateFake ( 2 ) );
yield return new TestCaseData ( CreateFake ( 4 ) );
}
public static IMyInterface CreateFake ( int something )
{
var fake = MockRepository.GenerateStub<IMyInterface> ();
fake.Stub ( x => x.Property ).Return ( something );
return fake;
}
}
}
I have been able to overcome the problem if I create a decorator class that wraps the generated stub:
public class Decorator : IMyInterface
{
IMyInterface decorated;
public Decorator ( IMyInterface decorated )
{
this.decorated = decorated;
}
public int Property
{
get
{
return decorated.Property;
}
}
}
And change the prior return fake; by return new Decorator ( fake );. Everything works fine then.
However this is a bit of a pain in my real scenario because my interface does not only have a single property as in this example but is more complex (and yes I know that VS2015 can generate the code for implementing through the decorated field, but that's not the point). Besides, it feels pointless to use RinhoMocks if I am going to end up creating an implementation of the interface I am wishing to not fully implement for my test purposes.
Anyway, what annoys me is that I do not understand why it does not work and therefore I ask:
Can anyone help me to understand why the code without the decorator did not work?
At discovery time, TestExplorer creates a process and asks our adapter to find tests. Your TestCaseSource method runs and generates the cases. It has a name generated by Moq.
Much later in the lifetime of the program, your test is executed by Visual studio, which creates a different process and asks the adapter to run the tests. Since we are running in a new process, the adapter has to discover (that is generate) the cases all over. Most likely, Moq generates them with a different name. The originally created cases are never run and NUnit runs these new cases, which, from the point of view of TestExplorer, were never discovered in the first place.
I haven't seen this symptom before, but we have a similar problem with random arguments being regenerated at execution time. It's essentially a problem with the architecture and could only be resolved if the Adapter could somehow keep the originally loaded test assembly around to be found by the execution process.

COM-object was released unintendedly

I have a helper-class for my unit-tests that share a reference to an COM-object in memory:
public class UnitTestGeometryProvider
{
public static readonly IGeometry Geometry = Deserialize();
}
The geometry is deserialized from a Xml file which is stored as a resource file and appended to the project. Afterwards it is wrapped into a COM object:
public static IGeometry Deserialize()
{
return (IGeometry) new XMLSerializerClass().LoadFromString(myXDoc.OuterXml, null, null);
}
Now I have two test-methods that use the geometry stored within this class:
[TestClass()]
public class MyTest
{
[TestMethod()]
public void FirstTest()
{
var p = UnitTestGeometryProvider.Geometry;
}
[TestMethod()]
public void SecondTest()
{
var p = UnitTestGeometryProvider.Geometry;
}
}
When running the second one I get a COMException:
COM object that has been separated from its underlying RCW cannot be used
I wonder why the reference to the COM-object is released as it is marked static in UnitTestGeometryProvider and I do not explicitly release it. So even if the managed resource to the instance would go out of scope (which is does not at it is static), the underlying COM object should go away only when all my tests finished or more general when the application terminates, or do I miss anything?
I am using ArcObjects and Visual NUnit.
Due to the comments by Hans Passant I found the actual problem.
Obviously the Visual-NUnit-Framework decides to create a separate thread for every test. Thus whenever I create a COM-object - be it static or not - this object lives on this single thread and cannot be used in another one. If the thread dies also does the COM-object or to be more precise the reference to it. This leads to the GC kicking in throwing the COM-object away as no more managed references to it exist within that thread.
The solution is pretty straitforward: I changed the static field to instance-members and created an instance-member of type UnitTestGeometryProvider within my test-class. Thus a new provider is generated by every test.
However this solution is quite annoying because the Geometry-property has to be initialized and therefor the Deserialize-method runs for every test instead of only once for all tests.
I donĀ“t know if there is a thread-safe solution to not kill the reference to the COM-object when the first thread that intialized it dies.

UnityContainer.RegisterType does not get used when put in a Static Constructor

This is an example console application (it will run fine after adding the Unity NugGet package) that seems to show a bug in Unity:
using System;
using Microsoft.Practices.Unity;
class GC { public static UnityContainer Container = new UnityContainer();}
class Program
{
static void Main(string[] args)
{
GC.Container.RegisterType<MyView>();
var myView = GC.Container.Resolve<MyView>();
Console.ReadLine();
}
}
public class MyClassDesign: MyClass{}
public class MyClass: VMBase<MyClass, MyClassDesign>{}
public abstract class VMBase<TViewModel, TDesignVM> where TDesignVM:TViewModel
{
static VMBase()
{
if (!GC.Container.IsRegistered(typeof(TViewModel)))
GC.Container.RegisterType(typeof (TViewModel), typeof(TDesignVM));
}
}
public class MyView
{
public MyView(MyClass myClass)
{
Console.WriteLine("Bad: "+myClass.GetType().ToString());
Console.WriteLine("Good: "+GC.Container.Resolve<MyClass>().GetType());
}
}
The output is:
Bad: MyClass
Good: MyClassDesign
The resolved type is MyClass. But it should be MyClassDesign. (The static constructor runs prior to MyClass being resolved in the MyView class.)
How can I get Unity to allow me to setup my Mapping in the Static Constructor?
Note: When I changed this setup the UnityContainer with a file (instead of in code) it all works fine. But I would rather not be dependent on an external file for this. (I am making a reusable template that I don't want to have too many dependencies in.)
Why do you want to put the registration logic inside your view model at all? This couples your application code to the container which is never a good idea. Have a look at the concept of Composition roots.
All setup code for the DI container should be placed there.
This isnt really a bug with Unity. The issue is that the static ctor is not run until an instance is requested (at which point unity still does not know about MyClassDesign). Which means that Unity has already started creating an instance of MyClass to fulfill the request. Any subsequent calls to GC.Container.Resolve<MyView>(); will result in the output you expect. As Sebastian Weber suggests, putting all your setup code in a completely seperate location (so your classes are not dependent on a specific DI container) is the best option.

.NET Remoting and HttpContext.Current

We have a plugin system where the plugin code runs on a separate AppDomain from the main process, using .NET remoting for the objects to communicate.
One class is similar to HttpContext.Current (which also suffers from the problem) (edit, the actual implementation):
public class MyClass
{
public static MyClass Instance
{
get
{
if(HttpContext.Current != null)
return HttpContext.Current.Items["MyClassInstance"];
}
set
{
if(HttpContext.Current != null)
HttpContext.Current.Items["MyClassInstance"] = value;
}
}
}
Then, we have a communicating object which inherits from MarshalByRefObject:
public class CommunicatingClass : MarshalByRefObject, ICommunicatingClass
{
public void DoSomething()
{
MyClass.Instance.DoSomething();
}
}
The CommunicatingClass is created on the main AppDomain, and works fine. Then, there's the plugin class, which is created on its AppDomain, and given an instance of the CommunicatingClass:
public class PluginClass
{
public void DoSomething(ICommunicatingClass communicatingClass)
{
communicatingClass.DoSomething();
}
}
The problem is, that even though CommunicatingClass resides on the main appdomain (verified with the Immediate Window), all of the static data such as MyClass.Instance and HttpContext.Current have disappeared and are null. I have a feeling that MyClass.Instance is somehow being retrieved from the plugin AppDomain, but am unsure how to resolve this.
I saw another question that suggested RemotingServices.Marshal, but that did not seem to help, or I used it incorrectly. Is there a way that the CommunicatingClass can access all static methods and properties like any other class in the main AppDomain?
Edit:
The PluginClass is given an instance like this:
public static PluginClass Create()
{
var appDomain = GetNewAppDomain();
var instance = (PluginClass)appDomain.CreateInstanceAndUnwrap(assembly, type);
instance.Communicator = new CommunicatingClass();
return instance;
}
Edit 2:
Might have found the source of the problem. MyClass.Instance is stored in HttpContext.Current.Items (see above edit).
Is there any way at all that HttpContext.Current can access the correct HttpContext? I'm still wondering why, even though it is being run in HttpContext.Current's AppDomain, CommunicatingClass.DoSomething, when calling MyClass.Instance, retrieves stuff from PluginClass' AppDomain (if that makes any sense).
So my co-worker and I worked this out, finally, with a bunch of help from Reflector.
The main problem is that HttpContext.Current is null when accessed via a remoting call.
The HttpContext.Current property is stored in an interesting manor. A few nested setters down, you reach CallContext.HostContext. This is a static object property on a CallContext.
When the CallContext is set, it first checks if the value is an ILogicalThreadAffinitive.
If it is, it stores the value in the current thread's LogicalCallContext.
If it's not, it stores the value in the current thread's IllogicalCallContext.
HttpContext is not an ILogicalThreadAffinitive, so it is stored in the IllogicalCallContext.
Then, there's remoting.
We didn't dig too far in to its source, but what it does was inferred from some other functions.
When a call is made to a remote object from a different AppDomain, the call is not directly proxied to the original thread, running in the exact same execution context.
First, the ExecutionContext of the original thread (the one containing HttpContext.Current) is captured, via ExecutionContext.Capture (more in this in a bit).
Then, the ExecutionContext returned from Capture is passed as the first argument to ExecutionContext.Run, esentially forming the code:
Delegate myRemoteCall; //Assigned somewhere else in remoting
ExecutionContext.Run(ExecutionContext.Capture(), x => { myRemoteCall() }, null);
Then, completely transparently, your code in the remote object is accessed.
Unfortunately, HttpContext.Current is not captured in ExecutionContext.Capture().
Here lies the essential difference between an IllogicalCallContext and a LogicalCallContext.
Capture creates a brand-new ExecutionContext, essentially copying all of the members (such as the LogicalCallContext) in to the new object. But, it does not copy the IllogicalCallContext.
So, since HttpContext is not an ILogicalThreadAffinative, it cannot be captured by ExecutionContext.Capture.
The solution?
HttpContext is not a MarshalByRefObject or [Serializable] (probably for good reason), so it cannot be passed in to the new AppDomain.
But, it can cross ExecutionContexts without problem.
So, in the main AppDomain's MarshalByRefObject which is given as a proxy to the other AppDomain, in the constructor give it the instance of HttpContext.Current.
Then, in each method call of the new object (unfortunately), run:
private HttpContext _context;
private void SyncContext()
{
if(HttpContext.Current == null)
HttpContext.Current = _context;
}
And it will be set without problem. Since HttpContext.Current is tied to the IllogicalCallContext of the ExecutionContext, it will not bleed in to any other threads that ASP.NET might create, and will be cleaned up when the copy ExecutionContext is disposed.
(I could be wrong about much of this, though. It's all speculation and reflection)
I believe you'll need to derive MyClass from MarshalByRefObject as well.

Categories

Resources