Solved

Dynamically Run Code

Posted on 2004-08-17
8
333 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
MS Dynamics Made Instantly Simpler

Make Your Microsoft Dynamics Investment Count  & Drastically Decrease Training Time by Providing Intuitive Step-By-Step WalkThru Tutorials.

 
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: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering 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
MYSQL responding very slow 3 67
vb.net deleting excel sheet in workbook 11 55
Telerik RadEditor Control Save 8 39
AD Computer Objects in VB .Net 2 16
Well, all of us have seen the multiple EXCEL.EXE's in task manager that won't die even if you call the .close, .dispose methods. Try this method to kill any excels in memory. You can copy the kill function to create a check function and replace the …
A while ago, I was working on a Windows Forms application and I needed a special label control with reflection (glass) effect to show some titles in a stylish way. I've always enjoyed working with graphics, but it's never too clever to re-invent …
Nobody understands Phishing better than an anti-spam company. That’s why we are providing Phishing Awareness Training to our customers. According to a report by Verizon, only 3% of targeted users report malicious emails to management. With compan…

734 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