Sacred Cows Make Great SteaksLink Round-Up for 10/10/07

How To Create Application Plug-ins In VB.NET

October 9th, 2007

Plugging into an appSooner or later you’ll find that you want to make your application extensible. Perhaps you want to add customer specific processing modules to your backend processes. Maybe you’ll want to offer customers the ability to add their own functionality to your base application. VB.NET and the .NET Framework make this relatively easy to do. Let’s walk through the steps.

Define an Interface

The way to load a .NET assembly dynamically is through reflection. To make this process easier and more controllable within the context of an application I’ve found it best to define a plug-in interface, such as this one:

Public Interface IMyPlugIn

    Function TestFunction(ByVal value As String) As String

    Property MySetting() As String

End Interface

By using the interface this allows us to have a fixed definition for our plug-ins that our main application to work with. This means that we will need less main app code to support our plug-in.

Create A Class

Now we’re ready to create a plug-in class. Here’s the template that gets created:

Public Class CustomerXYZPlugin
    Implements MyPlugIn.IMyPlugIn

    Public Property MySetting() As String Implements MyPlugIn.IMyPlugIn.MySetting
        Get

        End Get
        Set(ByVal value As String)

        End Set
    End Property

    Public Function TestFunction(ByVal value As String) As String Implements MyPlugIn.IMyPlugIn.TestFunction

    End Function

End Class

Now, to complete the plug-in class we will need to add appropriate code it. You can’t define constructors in an interface so you’ll find it best to specify that you’ll either use a parameterless constructor or require that plug-in classes support a specific set of parameters. My preference has been to use parameterless ones and to supply ample properties for the plug-ins.

As for other code, as long as you define the interface you can do just about anything else you want.

Loading The Plug-In

Now we get to the heart of the matter, how to load the plug-in. There are several approaches you can take to this but here’s mine. First, let’s look at the code:

Private Function LoadPlugIn(ByVal LoadPath As String) As MyPlugIn.IMyPlugIn
    Dim NewPlugIn As MyPlugIn.IMyPlugIn
    Try
        Dim PlugInAssembly As Reflection.Assembly = Reflection.Assembly.LoadFrom(LoadPath)
        Dim Types() As Type
        Dim FoundInterface As Type
        Types = PlugInAssembly.GetTypes
        For Each PlugInType As Type In Types
            FoundInterface = PlugInType.GetInterface("MyPlugIn.IMyPlugIn")
            If FoundInterface IsNot Nothing Then
                NewPlugIn = DirectCast(PlugInAssembly.CreateInstance(PlugInType.FullName), MyPlugIn.IMyPlugIn)
                Exit For
            End If
        Next
    Catch ex As Exception
        'handle exceptions here
    End Try
    Return NewPlugIn
End Function

As you can see, we’re passing in the path to our plug-in and returning a plug-in interface object from the call. After declaring our return value we enter a try block. I recommend putting this loader logic in an exception handling block since you may be dealing with code that’s outside your direct control.

Next, we create a new Reflection.Assembly object from the file location that was passed into our function and extract the types from it. This allows a plug-in to have functionality beyond just the interface. We search for our interface and, when we find it, create a new instance and exit our search loop. Then we pass back the newly created plug-in object back to our main code.

Here’s a simple example of what the main code might look like:

Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim NewPlugIn As MyPlugIn.IMyPlugIn = LoadPlugIn(TextBox1.Text)
    NewPlugIn.MySetting = "Hello World"
    Dim OurTestPlugInValue As String = NewPlugIn.TestFunction("Try It!")
End Sub

Those are the steps to adding a simple plug-in to your application. Of course, there are more things you can do with Reflection and I suggest that you investigate them if you’re thinking about implementing this in one of your apps. Remember that there is a performance penalty for using Reflection and there are security considerations as well so make sure you factor them into your design.

If you have any questions or observations about using Reflection to create plug-ins, let me know by leaving a comment.

Share This Article: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • DotNetKicks
  • DZone

Entry Filed under: Code Examples, VB.NET Tutorials


Rate This Article:

Not That GoodCould Be BetterOKGoodGreat (3 votes, average: 4.67 out of 5)
Loading ... Loading ...

9 Comments Add your own

  • 1. MikeP  |  October 10th, 2007 at 11:22 am

    Will this work for web apps too?

    How do you keep up with which DLL you need to load in a situation?

  • 2. jfrankcarr  |  October 10th, 2007 at 1:56 pm

    Yes, it will work for web apps. You do have to be more mindful of the performance hit though. It can be particularly effective for background processes called from a web interface or through a web service. This can allow you to add additional services for specific customers easily.

    As for keeping up with the DLLs I store the location of a client’s specific DLL in their account record in the DB.

  • 3. Karl Stoney  |  November 5th, 2007 at 7:31 am

    Hi,
    This is really great i’ve been searching for somthing like this for ages, but i’m still having difficulty grasping reflection, would you send me an example project + plugin ? I would really appreciate it.

    Karl.

  • 4. jfrankcarr  |  November 5th, 2007 at 11:47 am

    Hi Karl,

    Check out my new post: Application Plug-ins Code Example Update. Follow the instructions in that article and you should be good to go.

  • 5. Mike  |  January 29th, 2008 at 2:28 pm

    Doesn’t the assembly remain loaded though? I’d like to be able to update the plug-in while my program is still running.
    Can you not just reference a DLL and achieve the same effect?

  • 6. Jouke  |  September 1st, 2008 at 4:29 am

    Is it possible for the plugin to get info from the host?

  • 7. leizel  |  January 21st, 2009 at 8:29 pm

    hi,
    can you show me an example of program of for loop and if else for vb6.

  • 8. yousif  |  July 14th, 2009 at 11:53 am

    thanks allot !!

    i get the main idea

    but the question is how do i know that the plug-in would not do any bad thing to my app ??

  • 9. Samsonov  |  August 17th, 2009 at 5:17 am

    Those techniques with GetType / GetInterface are “not CLS-compliant” (as VB help claims). There is a more easier and graceful way to do things — just to create objects by their class name, not by an abstract interface type. Of course, it assumes that the plugin is a class library, but I think that’s the case in the majority of situations.

    For example, plugin’s code:

    Public Class MyPluginImplementation Inherits MyPluginBase
    .....{code must include constructor with no arguments}.....
    End Class

    And the application code:

    Dim oAssembly As Reflection.Assembly = Reflection.Assembly.LoadFrom(sFile)
    Dim oInstance As MyPluginBase = DirectCast(oAssembly.CreateInstance("RootNamespace.Namespace.MyPluginImplementation"), MyPluginBase)
    If Not IsNothing(oInstance) Then .....{do something}.....

Leave a Comment

Required

Required, hidden

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed


Visit Me At My New Site, Programming In C#

Most Popular Articles

Highest Rated Articles

Categories

Most Recent Articles

Feeds

 Subscribe in a reader

To subscribe by e-mail
Enter your address here

Delivered by FeedBurner

VB Opportunities

Archives