Solved

Dynamically Run Code

Posted on 2004-08-17
8
323 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
 
LVL 96

Author Comment

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

Thanks,
Bob
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

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…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
When you create an app prototype with Adobe XD, you can insert system screens -- sharing or Control Center, for example -- with just a few clicks. This video shows you how. You can take the full course on Experts Exchange at http://bit.ly/XDcourse.
I designed this idea while studying technology in the classroom.  This is a semester long project.  Students are asked to take photographs on a specific topic which they find meaningful, it can be a place or situation such as travel or homelessness.…

947 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

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now