AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=815&pId=-1
Plug In Application Using Reflection
page
by John Spano
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 7658/ 14

Microsoft .NET has an interesting and very useful concept called Reflection.  Since your compiled programs in .NET are compiled to IL and not machine code, it is very easy to query an EXE or DLL for the information it exposes in the form of classes, methods and properties, etc.  In this article, I will show you how to create a very simple and easy method for "plug-in" type architectures.

Our project will consist of 2 DLL's and one EXE.  Our EXE will show a ListBox and fill it with any of the strings of information it finds in compatible classes.  When you double click on the box, it will dynamically call the corresponding class that placed the string in the box.  Our regular class will have one string and our plug-in class will have another, if the EXE finds the DLL in its directory.

As with all good architectures, we will start with an interface.  The interface defined below will be the contract between our main EXE and any plug-in DLLs that exist.  We put the interface in its own DLL so other people can use it.  It is typical to have a DLL that is specifically for your interfaces.  This allows any other projects to get to them easily.  You can also have more control over the distribution of it when others want to add plug-ins to your application.  Ours is simple for this demo, but it can be as complex as you need it to be.  Here is its definition:

Listing 1

Public Interface IShowInListBox 
  Property TextValue() As String 
  Sub SayHello() 
End Interface 

It has a single property and a sub.  The property will return the line of text that we want to show in the ListBox.  The sub will be the code that gets fired when we double click on the item in the list box.  Any class that wants to be recognized by our main EXE as a plug-in will have to implement this interface.

We will now look at our two classes that will implement this interface.  One class is in our main EXE.  This one will function as the "standard functionality" of our app.  The other class is in our second DLL.  This one will function as our plug-in class.  Here are the definitions.

First the standard one:

Listing 2

Imports System.Windows.Forms
Public Class MyListItem
  Implements ReflectionInterfaces.IShowInListBox
 
  Sub SayHello() Implements ReflectionInterfaces.IShowInListBox.SayHello
    MessageBox.Show("Hello from My Exe!")
  End Sub
 
  Property IShowInListBox_TextValue() As String _
                                    ImplementsReflectionInterfaces.IShowInListBox.TextValue
    Get
    Return "ListBox Item From Exe"
    End Get
    Set(ByVal Value As String)
    End Set
  End Property
End Class

Here is the plug-in class.

Listing 3

Imports System.Windows.Forms
 
Public Class DllListItem
  Implements ReflectionInterfaces.IShowInListBox
 
  Sub SayHello() ImplementsReflectionInterfaces.IShowInListBox.SayHello
    MessageBox.Show("Hello from a DLLClass!")
  End Sub
 
  Property IShowInListBox_TextValue() As String _
                                    ImplementsReflectionInterfaces.IShowInListBox.TextValue
    Get
    Return "ListBox Item From a DLL Class"
    End Get
    Set(ByVal Value As String)
    End Set
  End Property
 
End Class

You will notice that they are almost exactly the same.  The only differences being their names, what they show in the message box and the strings they return to show in the list box.  Notice that both of the classes implement ReflectionInterfaces.IShowInListBox.  ReflectionInterfaces is the name of the namespace I put our interface in.

Now we will examine the main working code in our EXE.  It will load our standard class in the ListBox and then search for classes in our plug-in DLL that implement our interface and load them.  To show that it picks up only classes that implement IshowInListBox, I created another class that does not implement it and placed it in the DLL.  Its definition is very simple and is as follows:

Listing 4

Public Class NonListItem 
End Class 

And now our main EXE:

Listing 5

Imports System.Reflection
Imports ReflectionInterfaces
 
Private Sub Form1_Load(ByVal sender AsSystem.ObjectByVal e As System.EventArgs) Handles MyBase.Load
  Dim myCls As MyListItem = New MyListItem
  lstListBox1.DisplayMember = "TextValue"
  lstListBox1.Items.Add(myCls)
  LoadFromFoundDll()
End Sub
 
Private Sub LoadFromFoundDll()
  Dim assemblyObj As Reflection.Assembly = _
Reflection.Assembly.LoadFrom("C:\VBNetProjects\ReflectionArticle\bin\ReflectionDll.Dll")
  Dim types() As Type
  Dim FoundInterface As Type
  Dim o As Object
  types = assemblyObj.GetTypes
  For Each tp As Type In types
    Try
    FoundInterface =tp.GetInterface("IShowInListBox")
    If Not FoundInterface Is Nothing Then
      o = assemblyObj.CreateInstance(tp.FullName)
      Dim oLst As IShowInListBox
      oLst = DirectCast(o, IShowInListBox)
      lstListBox1.Items.Add(oLst)
    End If
    Catch
    Finally
    FoundInterface = Nothing
    End Try
  Next
End Sub
 
Private Sub lstListBox1_DoubleClick(ByVal sender AsObject, ByVal e As System.EventArgs) _
Handles lstListBox1.DoubleClick
  Dim oLst As IShowInListBox
  Dim Lst As ListBox
  Lst = DirectCast(sender, ListBox)
  oLst = DirectCast(Lst.SelectedItem,IShowInListBox)
  oLst.SayHello()
End Sub

It is a single form with a ListBox on it.  I have added a reference to my interface DLL and the corresponding imports for it and also for System.Reflection to get our reflection classes we will use.  Now I will explain the high points of the code.

If we start in the form load event, you see that I am setting up a new instance of my standard class and adding it to the list box.  The key thing to notice here is that I am adding the entire object and not just the text from its property.  This is one of .NET's strong points.  I can assign anything to the list box, even whole objects, and pull them out later.  I also can tell the list box to display the TextValue property of any object that is loaded into it.  How do you think it displays text of object that it only knows the name of the property of?  If you said reflection you would be right!  It uses it internally to dynamically call the property you specify.  After loading the standard class we then call a function that will load our plug-in class.

In our LoadFromFoundDll we hard code the name of the DLL for simplicity.  You could change this to search the application’s path for all DLL’s that have classes in them that implement our interface or have it look in the registry for the paths and names of the DLL’s it is supposed to load to make it more useful.

First we want to load our DLL in to memory using the assembly class.  After it is loaded, we can query the DLL for all its classes, which we do by asking for its types and loading them into an array.  We then loop through the array and query it to see if it supports our interface.  If it does, we create an object of the class and load it into our list box.

Now for our last function, the double click event of the ListBox.  In this function, we want to dynamically call the correct object when the user double clicks on it.  Since we have the interface as our contract, it is very simple to convert the returned object form the list box into an object of our interface and run the correct subroutine.

 

Summary

As you can see, creating a plug-in architecture in .NET is much easier than it used to be in VB6.  Reflection allows you to create a robust dynamic application that your end users will appreciate.  It also allows you to control what end functionality the user gets and allows for easier partial patching of your system when you find bugs in specific plug-ins.  In a later article, we will examine how to read all information from an assembly in .NET.


Product Spotlight
Product Spotlight 

©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-03-29 11:17:31 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search