Dynamically Run Code
Posted on 2004-08-17
Okay, I've struggled with this long enough, and I was hoping that somebody can give me a direction to go in that would provide a better solution. I am using the following code in VB.NET 2003 to dynamically compile and run some code that is loaded from a text file:
Public Function Compile(ByVal codeExecute As String, ByVal className As String, _
ByVal outputName As String, ByRef arrayErrors As ArrayList) As Boolean
' Assume success.
Dim boolValid As Boolean = True
arrayErrors = New ArrayList
Dim providerVB As New VBCodeProvider
Dim compilerVB As ICodeCompiler = providerVB.CreateCompiler
Dim paramCompiler As New CompilerParameters
paramCompiler.GenerateInMemory = False
'note it saves it in a temporary folder "user temp folder"
'also note you could enhance this by pulling the namespace info
'and class name from the code instead of having seperate vars for them.
paramCompiler.OutputAssembly = outputName & ".dll"
paramCompiler.MainClass = className
paramCompiler.IncludeDebugInformation = True
'I believe this is to get all the assemblies of the current
'application and add them as references to the new assembly
For Each assemblyVB As [Assembly] In AppDomain.CurrentDomain.GetAssemblies()
'here we do the deed
Dim resultsCompile As CompilerResults = compilerVB.CompileAssemblyFromSource(paramCompiler, _
'this is just to list out all the errors if any
For Each errorCompile As CompilerError In resultsCompile.Errors
If arrayErrors.Count = 0 Then
'now we create an instance of the assembly newly created
'and set it to an object notice this is also a good example of late binding
Dim vArgs() As Object
Dim nsName As String = Me.GetType.Assembly.GetEntryAssembly().GetName().Name
Dim fullName = nsName & "." & outputName & "." & className
Dim objectName As String = nsName & "." & className
Dim objectRun As Object = resultsCompile.CompiledAssembly.CreateInstance(objectName)
Dim typeClass As Type = resultsCompile.CompiledAssembly.GetType(objectName)
Dim methodShowDialog As MethodInfo = typeClass.GetMethod("Test")
'now we call the sub in the object
Dim vParams() As Object
'Dim domainRun As AppDomain = AppDomain.CreateDomain("Run", AppDomain.CurrentDomain.Evidence)
'Dim assemblyRun As [Assembly] = domainRun.Load(domainRun.RelativeSearchPath & "\" & outputName & ".dll")
boolValid = False
resultsCompile = Nothing
providerVB = Nothing
paramCompiler = Nothing
compilerVB = Nothing
End Function 'Compile'
It is a small test code that works correctly once:
Public Class TestClass
Public Sub Test
The problem comes when I try to make a change to the file and run it again. I get an error that the assembly cannot be recompiled since it is still in use. This is because the assembly is still in memory, and cannot be unloaded. I have tried to overcome this by creating a new AppDomain (commented code towards the bottom), and Loading the compiled assembly in the new AppDomain, and then Unloading the domain when I am through.
When I tried this, I kept getting an error that the DLL or one of its dependencies could not be found (Man, I hate this error!) :(
This may not be the best approach, and I am open to any kind of suggestions, hints, links, etc., that could help me find a solution to this problem.
Bob "The Learned One"