Click here to Skip to main content
Click here to Skip to main content

Dynamic Console App for Invoking .NET Assemblies

, 18 Oct 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
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...

Imports System.Reflection 

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

msgHan = Assembly.LoadFile(assemblyFilePath)

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

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.

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:

 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.

 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.

 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.

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)

Share

About the Author

Yang Yu
Architect Prognex Corp.
Canada Canada
Love startups, programming, and machine learning.
 
CEO and Founder of FansFave.com
 
LinkedIn: http://www.linkedin.com/in/mryuyang
Twitter: http://twitter.com/mryangyu

Comments and Discussions

 
QuestionC# PinmemberDoncp19-Oct-07 7:40 
Why is this shown as a C# project?
 
Looks like a VB project to me.
 
Smile | :)
Don
AnswerRe: C# Pinmemberyang yu 179999926-Oct-07 5:01 
QuestionGood, but is it necessary? PinmemberNeil Barnwell18-Oct-07 12:49 
AnswerRe: Good, but is it necessary? PinmemberMarc Leger24-Oct-07 0:14 
GeneralCool PinmemberJonathan [Darka]18-Oct-07 9:21 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.1411023.1 | Last Updated 18 Oct 2007
Article Copyright 2007 by Yang Yu
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid