vb.netcompiler-errorscodedomsystem-codedom-compiler

System.CodeDom.Compiler Interface IScript not defined


I used the following answers to test compile code:

https://stackoverflow.com/a/21382083/9942758

https://stackoverflow.com/a/14711110/9942758

Here is my code:

    Public Interface IScript
        Property theDataTable As System.Data.DataTable
        Sub DoWork()
    End Interface

    Public Function GenerateScript(code As String) As IScript

        Using provider As New VBCodeProvider()

            Dim parameters As New CompilerParameters()

            parameters.GenerateInMemory = True
            parameters.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location)
            parameters.ReferencedAssemblies.Add("System.Data.dll")
            parameters.ReferencedAssemblies.Add("System.Xml.dll")
            parameters.ReferencedAssemblies.Add("C:\Users\<User>\source\repos\MikroTikTable\MikroTikTable\bin\Debug\Renci.SshNet.dll")

            Dim interfaceNamespace As String = GetType(IScript).Namespace
            Dim codeArray() As String = New String() {"Imports " & interfaceNamespace & Environment.NewLine & code}
            Dim results As CompilerResults = provider.CompileAssemblyFromSource(parameters, codeArray)

            If results.Errors.HasErrors Then
                Throw New Exception("Failed to compile script")
            Else
                Return CType(results.CompiledAssembly.CreateInstance("Script"), IScript)
            End If
        End Using
    End Function

    Public Function GetTable(theHost As String, theUser As String, thePwd As String, theCmd As String) As DataTable

        Dim builder As New StringBuilder()

        builder.AppendLine("Imports Renci.SshNet")
        builder.AppendLine("Imports System.Data")
        builder.AppendLine("Imports Microsoft.VisualBasic")
        builder.AppendLine("Imports System.Text")
        builder.AppendLine("Imports System.Text.RegularExpressions")
        'builder.AppendLine("Public Interface IScript")
        'builder.AppendLine("    Property theDataTable As DataTable")
        'builder.AppendLine("    Sub DoWork()")
        'builder.AppendLine("End Interface")
        builder.AppendLine("Public Class Script")
        builder.AppendLine("    Implements IScript")
        builder.AppendLine("    Public Property theDataTable As DataTable Implements IScript.theDataTable")
        builder.AppendLine("    Public Sub DoWork() Implements IScript.DoWork")
        builder.AppendLine($"        Dim theConnectionInfo As PasswordConnectionInfo = New PasswordConnectionInfo(""{theHost}"", ""{theUser}"", ""{thePwd}"")")
        builder.AppendLine("        Dim sshClient = New SshClient(theConnectionInfo)")
        builder.AppendLine($"        Dim sshCmd = ""{theCmd}"".Replace(vbCrLf, vbCr)")
        builder.AppendLine("         Dim cmdArgs As New clsCommandData With {.cmd = sshCmd}")
        builder.AppendLine("        sshClient.Connect()")
        builder.AppendLine("        cmdArgs.output = sshClient.RunCommand(cmdArgs.cmd)")
        builder.AppendLine("        Dim resultText = cmdArgs.output.Result.Replace(vbCr, """")")
        builder.AppendLine("        SshClient.Disconnect()")
        builder.AppendLine("        resultText = resultText.Replace(vbLf, vbCrLf)")
        builder.AppendLine("        resultText = Regex.Replace(resultText, ""^\s+$[\r\n]*"", ""|"", RegexOptions.Multiline)")
        builder.AppendLine("        Dim interfaceRows() = resultText.Split(""|"")")
        builder.AppendLine("        Dim newString As New StringBuilder")
        builder.AppendLine("        For i As Integer = 0 To interfaceRows.Length - 2")
        builder.AppendLine("            Dim interfaceRow = interfaceRows(i)")
        builder.AppendLine("            interfaceRow = interfaceRow.Replace(""|"", """")")
        builder.AppendLine("            interfaceRow = Trim(interfaceRow)")
        builder.AppendLine("            interfaceRow = interfaceRow.Replace(vbCrLf, "" "")")
        builder.AppendLine("             interfaceRow = Regex.Replace(interfaceRow, "" {2,}"", "" "")")
        builder.AppendLine("            Dim startPos = interfaceRow.LastIndexOf(""="")")
        builder.AppendLine("            Do While startPos > -1")
        builder.AppendLine("                Dim theSpacePos = interfaceRow.LastIndexOf("" "", startPos)")
        builder.AppendLine("                If theSpacePos > -1 Then interfaceRow = interfaceRow.Remove(theSpacePos, 1).Insert(theSpacePos, ""|"")")
        builder.AppendLine("                startPos = interfaceRow.LastIndexOf(""="", theSpacePos)")
        builder.AppendLine("            Loop")
        builder.AppendLine("            Dim fieldCandidates() = interfaceRow.Split(""|"")")
        builder.AppendLine("            For j As Integer = 1 To fieldCandidates.Length - 1")
        builder.AppendLine("                Dim fieldCandidate = fieldCandidates(j)")
        builder.AppendLine("                Dim splitField() = fieldCandidate.Split(""="")")
        builder.AppendLine("                If Not theDataTable.Columns.Contains(splitField(0)) Then theDataTable.Columns.Add(splitField(0), GetType(String))")
        builder.AppendLine("            Next")
        builder.AppendLine("            Dim addRow = theDataTable.NewRow")
        builder.AppendLine("            For j As Integer = 1 To fieldCandidates.Length - 1")
        builder.AppendLine("                Dim fieldCandidate = fieldCandidates(j)")
        builder.AppendLine("                Dim splitField() = fieldCandidate.Split(""="")")
        builder.AppendLine("                addRow(splitField(0)) = splitField(1)")
        builder.AppendLine("            Next")
        builder.AppendLine("            theDataTable.Rows.Add(addRow)")
        builder.AppendLine("        Next")
        builder.AppendLine("    End Sub")
        builder.AppendLine("    Private Class clsCommandData")
        builder.AppendLine("        Public cmd As String")
        builder.AppendLine("        Public output As SshCommand")
        builder.AppendLine("    End Class")
        builder.AppendLine("End Class")

        'Dim theText = builder.ToString()
        Dim script As IScript = GenerateScript(builder.ToString())

        script.DoWork()

        Return script.theDataTable
    End Function

I keep on getting compiler error "Type 'IScript' is not defined"

If I explicitly define the IScript Interface in my stringbuilder I get no compiler error, but then casting from "Class Script" to IScript fails.

What am I missing here?


Solution

  • Start from here, which works, and add back what I removed. Basically, this code sees the Interface, so there must be some other issue.

    Imports System.CodeDom.Compiler
    Imports System.Reflection
    
    Module Module1
        Sub Main()
            Dim bar = New Foo()
            Dim dt = bar.GetTable()
        End Sub
    End Module
    
    Public Interface IScript
        Property theDataTable As System.Data.DataTable
        Sub DoWork()
    End Interface
    
    Public Class Foo
        Public Function GenerateScript(code As String) As IScript
            Using provider As New VBCodeProvider()
                Dim parameters As New CompilerParameters()
                parameters.GenerateInMemory = True
                parameters.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location)
                parameters.ReferencedAssemblies.Add("System.Data.dll")
                parameters.ReferencedAssemblies.Add("System.Xml.dll")
                Dim interfaceNamespace As String = GetType(IScript).Namespace
                Dim codeArray() As String = New String() {"Imports " & interfaceNamespace & Environment.NewLine & code}
                Dim results As CompilerResults = provider.CompileAssemblyFromSource(parameters, codeArray)
                If results.Errors.HasErrors Then
                    Throw New Exception("Failed to compile script")
                Else
                    Return CType(results.CompiledAssembly.CreateInstance("Script"), IScript)
                End If
            End Using
        End Function
        Public Function GetTable() As DataTable
            Dim text = "
    Imports System.Data
    Imports Microsoft.VisualBasic
    Public Class Script
        Implements IScript
        Public Property theDataTable As DataTable Implements IScript.theDataTable
        Public Sub DoWork() Implements IScript.DoWork
            MsgBox(""Hello"")
        End Sub
    End Class"
            Dim script As IScript = GenerateScript(text)
            script.DoWork()
            Return script.theDataTable
        End Function
    End Class