Are there any patterns that address how to have and application load and run user defined code at run-time? I am looking into developing a C# library that the users of a Test Executive application (app that interacts with HW to test mobile devices in development) can leverage to define test code (currently the tests are defined in xml through a rather cumbersome/poorly designed UI and we have had requests for some sort of library). The test code will need to be loaded and run by the application. The proposed approach is...
- Distribute Library of methods that a user can develop tests with
- Distribute a small framework with interfaces that should be implemented so that the application can locate test code.
- User compiles tests into DLLs from project that references DLLs from 1 and 2
- Application loads user supplied DLLs (generated in step 3) and locates test method (defined in framework from 2) via reflection on the DLL
- Application runs test code which should be a series of method calls from 1
- The library from 1 uses reflection so that each method call from the library maps to some series of calls defined within the running application assembly.
The user might write something that looks like this:
using MyFramework;
using MyLib;
namespace Test
{
public class MyTest : MyFramework.Test //defines the abstract RunTest method
{
public override void RunTest() { //user implements RunTest
//the test code
MyLib.Commands commands = new MyLib.Commands();
commands.Command1();
commands.Command2();
}
}
}
The code that the user writes will be compiled to a DLL and made available to the application. MyLib.Commands.Command1 would do this (illustration of point number 6):
public void Command1() {
Assembly exeAssembly = Assembly.LoadFile(@"C:\theAppThatRunsTheUserCode.exe");
Type typeInAppWhereLibCallsMapTo = exeAssembly.GetType("app.targetType");
MethodInfo methodMappedToLibCall = typeInAppWhereLibCallsMapTo.GetMethod("AppCommand1");
methodMappedToLibCall.Invoke(null, null);
}
The application would run user-code like this:
public void RunTheUserTest() {
Assembly dllAssembly = Assembly.LoadFile(@"C:\Test.dll");
Type testType = dllAssembly.GetType("Test.MyTest");
object myTestInstance = Activator.CreateInstance(testType);
MethodInfo runTestMethodInfo = testType.GetMethod("RunTest");
runTestMethodInfo.Invoke(myTestInstance, null);
}
Are there any well known design patterns that are better suited to solve this type of problem? I'm wondering if this is an okay approach. If not, what's wrong with it? Are there easier/"more elegant" ways to solve this type of problem?