Click here to Skip to main content
15,881,733 members
Articles / Programming Languages / Visual Basic
Article

Dynamic Console App for Invoking .NET Assemblies

Rate me:
Please Sign up or sign in to vote.
4.38/5 (4 votes)
18 Oct 2007CPOL3 min read 37.4K   188   24   5
This application demonstrates how .NET Reflection can be used to Query and Invoke Any Assemblies Methods.
Screenshot - Custom_Return_Type.jpg

Introduction

This is my first article on The Code Project. I will keep it brief and to the point.

The purpose of this application is to utilize .NET Reflection to create a console application that will load any .NET assembly, query all of its classes and objects, construct instances of these objects, and invoke its methods and properties. The current version still has a lot of bugs, but I will fix these bugs in the near future. But this gives you an idea of what I am trying to accomplish.

Background

The example I've provided in this article uses an Assembly called MessageHandler which is included in the solution.

To run the example, simply run the ReflectionText.exe "assembly path".

Using the Code

First we reference the Reflection Assembly...

VB.NET
Imports System.Reflection 

To load an assembly, we simply give the path of the assembly file.

VB.NET
msgHan = Assembly.LoadFile(assemblyFilePath)

To get a list of all the Types, we will need to call the GetTypes method of that Type object.

VB.NET
Dim types As Type() = msgHan.GetTypes()  

A Type object is a blue print of the signature of a specific Type. It holds information about its Methods, Properties, Variables, etc. It also contains meta information and constructor information.

Screenshot - Loading_Assembly.jpg

To Get a list of constructors of an instance class, we call the GetConstructor function.

A constructor is simply a method that is invoked when an instance of a class is created. It can be overloaded to create difference initial behaviors of that instance by passing in different parameters.

VB.NET
Dim cons As ConstructorInfo() = typMsg.GetConstructors()  

Screenshot - Invoking_Constructor.jpg

To show a list of parameters of a method, I've included this function in my code:

VB.NET
Private Function GetMethodSignature(ByVal method As MethodBase) As String
       If method Is Nothing Then Return Nothing
       Dim parms As ParameterInfo() = method.GetParameters()
       If parms Is Nothing OrElse parms.Length = 0 Then Return "()"

       Const COMMA As String = ", ", strAS = " as "

       Dim sb As New Text.StringBuilder(parms.Length * 50)

       sb.Append("(")

       For i As Integer = 0 To parms.Length - 1
           sb.Append(parms(i).Name)
           sb.Append(strAS)
           sb.Append(parms(i).ParameterType.Name)
           sb.Append(COMMA)
       Next
       'remove last comma
       If sb.Length > 1 Then sb.Remove(sb.Length - COMMA.Length, COMMA.Length)
       sb.Append(")")

       Return sb.ToString()
   End Function

The Object ParameterInfo contains information about a parameters Value Type, meta data, default values etc.

In the above code, I used a string builder to list out all the parameters of a method and its type in the way the function is written.

Screenshot - Loading_Methods.jpg

Once the parameters info is displayed, we can simply create an Array of Object Type that will hold the user input for a particular parameter, and convert it to the type of the parameter by using Convert.ChangeType. If the types does not have a converter, an exception will be thrown.

VB.NET
Private Function GetParamValues(ByVal parms As ParameterInfo()) As Object()
       Dim args(parms.Length - 1) As Object

       Console.WriteLine()
       Console.WriteLine(" ----- Parameters ----- ")
       For i As Integer = 0 To parms.Length - 1
           Dim parmType As Type = parms(i).ParameterType

           Console.WriteLine(parms(i).Name & ":")

           'set parameters setting to the type of parameter
           args(i) = Convert.ChangeType(Console.ReadLine(), parmType)
       Next
       Console.WriteLine(" ------------------- ")

       Return args
   End Function

Once we have collected the Parameter Values, we can simply invoke that particular method by using the Method.Invoke function which will execute that method on the same thread and return a value of Type Object.

In the example project I provided, I also included the number of times you want to invoke the method using Reflection for Unit Testing Purposes.

VB.NET
ret = meth.Invoke(clsMsg, args)

"ScreenshotAnd we are done.

I've included a function to display the information retrieved from the function with a recursive algorithm. Since a return value can be a complex data type, we can iterate through the return type, invoke the get property of all its properties, and have a better understanding.

VB.NET
Private Function GetClassFields(ByVal obj As Object) As String
        If obj Is Nothing Then Return String.Empty

        Dim sb As New Text.StringBuilder(256 * 500)

        Return GetClassProperties(obj, sb, 0) '+ GetClassFields(obj, sb, 0) 
    End Function

    Private Function GetClassProperties(ByVal obj As Object, _
        ByVal Sb As Text.StringBuilder, ByVal Depth As Integer) As String
        Dim objType As Type = obj.GetType()
        'create indent
        Sb.Append(Space(TAB_LENGTH * Depth))
        Sb.Append(".")
        Sb.Append(objType.Name)
        Sb.Append(vbNewLine)

        Try
            Dim props As PropertyInfo()
            props = objType.GetProperties()

            'if object is a list then show all list
            For i As Integer = 0 To props.Length - 1

                If props(i).CanRead Then
                    Dim getmeth As MethodInfo = props(i).GetGetMethod()

                    Dim ret As Object = Nothing

                    If getmeth.GetParameters().Length = 0 Then
                        'get property value
                        ret = getmeth.Invoke(obj, Nothing)
                    End If

                    If Not Depth < 10 AndAlso ret IsNot Nothing AndAlso _
                    Not ret.GetType().IsValueType AndAlso Not TypeOf (ret) _
                            Is String Then
                        Sb.Append(GetClassProperties(ret, Sb, Depth + 1))
                    Else
                        Sb.Append(Space(TAB_LENGTH * Depth + 1))
                        Sb.Append(".")
                        Sb.Append(props(i).Name)
                        Sb.Append(":")

                        If ret Is Nothing Then
                            Sb.Append(vbNewLine)
                            'check if object is a list
                            If TypeOf (obj) Is IEnumerable Then
                                For Each o As Object In obj
                                    Sb.Append(GetClassProperties(o, Sb, Depth + 1))
                                Next
                            End If
                        Else
                            Sb.Append(ret.ToString())
                        End If
                        Sb.Append(vbNewLine)
                        End If
                End If
            Next
            Return Sb.ToString()
        Catch ex As Exception
            Return Sb.ToString()
        End Try
    End Function

    Private Function GetClassFields(ByVal obj As Object, _
        ByVal Sb As Text.StringBuilder, ByVal Depth As Integer) As String
        Dim objType As Type = obj.GetType()
        'create indent
        Sb.Append(Space(TAB_LENGTH * Depth))
        Sb.Append(".")
        Sb.Append(objType.Name)
        Sb.Append(vbNewLine)

        Try
            Dim fields As FieldInfo() = objType.GetFields()

            For i As Integer = 0 To fields.Length - 1
                If fields(i).IsPublic Then
                    Dim ret As Object = fields(i).GetValue(obj)
                    If Not Depth < 10 AndAlso Not ret.GetType().IsValueType _
                        AndAlso Not TypeOf (ret) Is String Then
                        Sb.Append(GetClassFields(ret, Sb, Depth + 1))
                    Else
                        Sb.Append(Space(TAB_LENGTH * Depth + 1))
                        Sb.Append(".")
                        Sb.Append(fields(i).Name)
                        Sb.Append(":")
                        Sb.Append(ret.ToString())
                        Sb.Append(vbNewLine)
                    End If
                End If
            Next

            Return Sb.ToString()
        Catch ex As Exception
            Return Sb.ToString()
        End Try
    End Function
Screenshot - Custom_Return_Type.jpg

Points of Interest

Reflection can be very useful in many ways. You can use this as a base of a pluggable application.

This particular application can be used in a remote shell, or a BAT file to execute a particular process. It is kind of like the Windows Power Shell.

History

  • 18th October, 2007 - Draft of article posted

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Canada Canada
Engineer, maker, food lover

Comments and Discussions

 
QuestionC# Pin
Doncp19-Oct-07 6:40
Doncp19-Oct-07 6:40 
AnswerRe: C# Pin
Yang Yu26-Oct-07 4:01
Yang Yu26-Oct-07 4:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.