Solved

Dynamically Run Code

Posted on 2004-08-17
8
329 Views
Last Modified: 2010-04-23
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()
      paramCompiler.ReferencedAssemblies.Add(assemblyVB.Location)
    Next

    'here we do the deed
    Dim resultsCompile As CompilerResults = compilerVB.CompileAssemblyFromSource(paramCompiler, _
      codeExecute)

    'this is just to list out all the errors if any
    For Each errorCompile As CompilerError In resultsCompile.Errors
      arrayErrors.Add(errorCompile)
    Next

    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

      methodShowDialog.Invoke(objectRun, vParams)

      'Dim domainRun As AppDomain = AppDomain.CreateDomain("Run", AppDomain.CurrentDomain.Evidence)
      'domainRun.AppendPrivatePath(Path.GetDirectoryName([Assembly].GetExecutingAssembly.Location.ToString))

      'Dim assemblyRun As [Assembly] = domainRun.Load(domainRun.RelativeSearchPath & "\" & outputName & ".dll")

    Else

      boolValid = False

    End If

    resultsCompile = Nothing
    providerVB = Nothing
    paramCompiler = Nothing
    compilerVB = Nothing

  End Function 'Compile'


It is a small test code that works correctly once:

Imports System
Imports System.Windows.Forms

Namespace AutoBuild.NET
  Public Class TestClass
     Public Sub Test
       MessageBox.Show("test message")
    End Sub
  End Class

End Namespace


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.

TIA
Bob "The Learned One"
0
Comment
Question by:Bob Learned
  • 6
  • 2
8 Comments
 
LVL 10

Accepted Solution

by:
eternal_21 earned 500 total points
ID: 11832023
Change

  paramCompiler.GenerateInMemory = False

to

  paramCompiler.GenerateInMemory = True

and your problem will be solved!
0
 
LVL 96

Author Comment

by:Bob Learned
ID: 11832058
That is the way that I had it before, but I was still getting the error.  

I noticed, though, that when it was True, it was still creating a file in the assembly bin folder.  The GenerateInMemory = False was an attempt to get it to load into the AppDomain.

Bob
0
 
LVL 10

Expert Comment

by:eternal_21
ID: 11832874
> I noticed, though, that when it was True, it was still creating a file in the assembly bin folder.

The DLL will get created, but after being loaded, there will be no lock on the file.  Can you post some more code?  I was able to repeatly generate a DLL file and execute the Test method with out another AppDomain, and without any errors...
0
Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

 
LVL 96

Author Comment

by:Bob Learned
ID: 11832905
Let me check this again, I'll get back to you.

Thanks,
Bob
0
 
LVL 96

Author Comment

by:Bob Learned
ID: 11833049
Okay, I changed paramCompiler.GenerateInMemory = True, and now I don't get any error.  It must have been one of the 10,000 things that I was experimenting with that was causing my problem.  Now, I think I am back to the original problem that I lost track of, which is if I run the code, I get a message box, but if I change the text of the message box, and then try to recompile it, I get the old message box text.

This is the calling code:

  Private Sub RunScript()

    Dim richtextObject As RichTextBox
    Dim stringFileName As String

    Try

      richtextObject = Me.ActiveScriptControl
      stringFileName = Me.ActiveScriptFileName

      Dim errorMessage As String

      Dim compilerRunTime As New SourceCodeCompiler

      Dim boolValid As Boolean = compilerRunTime.Compile(richtextObject.Text, "TestClass", _
        "Test", errorMessage)

      If Not boolValid Then
        MsgBox(errorMessage)
      End If

      '      m_scriptEngine.SystemFont = Me.Font

      '     m_scriptEngine.RunScript(stringFileName, Me.ActiveScriptControl.Lines)

      buttonRun.Pushed = False

    Catch ex As Exception

      MsgBox(ex.ToString)

    End Try

  End Sub 'RunScript'


Thanks,
Bob
0
 
LVL 96

Author Comment

by:Bob Learned
ID: 11835191
This is the reference that I used to start thinking about creating a new  AppDomain:

http://www.dotnet247.com/247reference/msgs/33/166928.aspx

Bob
0
 
LVL 96

Author Comment

by:Bob Learned
ID: 11835325
Here is another that talks about AppDomains:

http://www.west-wind.com/presentations/dynamicCode/DynamicCode.htm

Bob
0
 
LVL 96

Author Comment

by:Bob Learned
ID: 11855593
I think what I will do is to split the compiler code, and put it into another application, and make the calling program write a temporary file, and then pass the name of the file to the compiler application, which will get unloaded once it is done.

Thanks for your help.
Bob
0

Featured Post

Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Set value of dynamically created checkboxlist 2 42
VB.Net - MemoryMappedFiles - Confirm receipt 2 24
MailAddress in vb 4 29
Code enhancement 4 22
Microsoft Reports are based on a report definition, which is an XML file that describes data and layout for the report, with a different extension. You can create a client-side report definition language (*.rdlc) file with Visual Studio, and build g…
If you need to start windows update installation remotely or as a scheduled task you will find this very helpful.

830 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question