Extend your .NET Applications with Add-ons

Extend your .NET Applications with Add-ons

Tutorial Details
  • Topic: Microsoft .NET Framework 4.0
  • Difficulty: Expert
  • Estimated Completion Time: 40 minutes

Your application lacks a cool whizbang feature? Let other interested developers extend your application through add-ons. By opening up your app to additional functionality down the line, you can build a thriving community around your application, potentially even a marketplace!

In today’s tutorial, we’re going to learn just that!


Step 0 – Our Game Plan

Depending on which version of Visual Studio you’re using, and the version of the framework you’re targeting, some screenshots may look slightly different.

We’re going to build a proof-of-concept application that, upon start-up, loads add-ons that it finds in one of its subdirectories. These add-ons are .NET assemblies that contain at least one class which implements a particular interface as defined by us. The concepts in this tutorial should be easily transferred into your existing applications without much hard work. Then we’ll look at a more complete example utilizing UI components loaded from an add-on.

This tutorial was written using Microsoft Visual Studio 2010, in VB.NET targeting .NET Framework 4.0. The salient concepts of this tutorial should work in other CLR languages, from .NET Framework 1.1 upwards. There is some minor functionality which will not work in other CLR languages – but should be very easily ported – and some concepts like generics which obviously won’t work in .NET 1.1 etc.

Note: This is an expert level tutorial for people happy with converting code between different CLR languages and versions of the .NET framework. It’s more ‘replacing your car engine’ than ‘how to drive’.


Step 1 – Initial Small Scale Implementation

Note: Your references may be different depending on which version of the .NET Framework you’re targeting.

Let’s start by implementing a small-scale version of our application. We will need three projects in our solution:

  • ConsoleAppA: A console application
  • ClassLibA: A class library
  • AddonA: A class library that will act as our add-on

Add a reference from both ConsoleAppA and and AddonA to ClassLibA. Solution explorer should then look as follows:

Creating the Add-on Interface

For a compiled class to be considered compatible, every add-on for our application will need to implement a specific interface. This interface will define the required properties and operations that the class must have so that our application can interact with the add-on without hitches. We could also use an abstract/MustInherit class as the basis for add-ons but in this example we’ll use an interface.

Here is the code for our interface, which should be placed in a file called IApplicationModule within the ClassLibA class library.

Public Interface IApplicationModule

    ReadOnly Property Id As Guid
    ReadOnly Property Name As String

    Sub Initialise()

End Interface

The properties and methods you define in the interface are arbitrary. In this case,, I have defined two properties and one method, but in practice you can and should change these as required.

We’re not going to use the Id or Name properties in our first example, but they’re useful properties to implement, and you’d probably want these present if you’re using add-ons in production.

Creating an Add-on

Now let’s create the actual add-on. Again, for any class to be considered an add-on for our application, it needs to implement our interface – IApplicationModule.

Here is the code for our basic add-on, which should be placed in a file called MyAddonClass within the AddonA class library.

Imports ClassLibA

Public Class MyAddonClass
    Implements IApplicationModule

    Public ReadOnly Property Id As System.Guid Implements ClassLibA.IApplicationModule.Id
        Get
            Return New Guid("adb86b53-2207-488e-b0f3-ecd13eae4042")
        End Get
    End Property

    Public Sub Initialise() Implements ClassLibA.IApplicationModule.Initialise
        Console.WriteLine("MyAddonClass is starting up ...")
        'Perform start-up initialisation here ...
    End Sub

    Public ReadOnly Property Name As String Implements ClassLibA.IApplicationModule.Name
        Get
            Return "My first test add-on"
        End Get
    End Property
End Class

Step 2 – Finding Add-ons at Runtime

Next, we need a way to find add-ons for our application. In this example, we’ll assume that an Addons folder has been created in the executable’s directory. If you’re testing this within Visual Studio, bear in mind the default project output directory for projects, namely ./bin/debug/, so you would need a ./bin/debug/Addons/ directory.

Time to Reflect

Place the TryLoadAssemblyReference method below into Module1 of ConsoleAppA. We investigate the loaded assembly through the use of Reflection. A pseudo-code walkthrough of its functionality is as follows:

  • Try to load the given dllFilePath as a .NET assembly
  • If we’ve successfully loaded the assembly, proceed
  • For each module in the loaded assembly
  • For each type in that module
  • For each interface implemented by that type
  • If that interface is our add-on interface (IApplicationModule), then
  • Keep a record of that type. Finish searching.
  • Finally, return any valid types found
    Private Function TryLoadAssemblyReference(ByVal dllFilePath As String) As List(Of System.Type)
        Dim loadedAssembly As Assembly
        Dim listOfModules As New List(Of System.Type)
        Try
            loadedAssembly = Assembly.LoadFile(dllFilePath)
        Catch ex As Exception
        End Try
        If loadedAssembly IsNot Nothing Then
            For Each assemblyModule In loadedAssembly.GetModules
                For Each moduleType In assemblyModule.GetTypes()
                    For Each interfaceImplemented In moduleType.GetInterfaces()
                        If interfaceImplemented.FullName = "ClassLibA.IApplicationModule" Then
                            listOfModules.Add(moduleType)
                        End If
                    Next
                Next
            Next
        End If
        Return listOfModules
    End Function

Firing up our Add-ons

Finally, we can now load a compiled class that implements our interface into memory. But we don’t have any code to find, instantiate, or make method calls on those classes. Next we’ll put together some code that does just that.

The first part is to find all files which might be add-ons, as below. The code performs some relatively straightforward file searching, and for each DLL file found, attempts to load all of the valid types from that assembly. DLLs discovered under the Addons folder aren’t necessarily add-ons – they could simply contain extra functionality required by an add-on, but not actually be an add-on per se.

        Dim currentApplicationDirectory As String = My.Application.Info.DirectoryPath
        Dim addonsRootDirectory As String = currentApplicationDirectory & "\Addons\"
        Dim addonsLoaded As New List(Of System.Type)

        If My.Computer.FileSystem.DirectoryExists(addonsRootDirectory) Then
            Dim dllFilesFound = My.Computer.FileSystem.GetFiles(addonsRootDirectory, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dll")
            For Each dllFile In dllFilesFound
                Dim modulesFound = TryLoadAssemblyReference(dllFile)
                addonsLoaded.AddRange(modulesFound)
            Next
        End If

Next we need to do something each valid type we’ve found. The code below will create a new instance of the type, type the type, call the Initialise() method (which is just an arbitrary method we defined in our interface), and then keep a reference to that instantiated type in a module level list.

        If addonsLoaded.Count > 0 Then
            For Each addonToInstantiate In addonsLoaded
                Dim thisInstance = Activator.CreateInstance(addonToInstantiate)
                Dim thisTypedInstance = CType(thisInstance, ClassLibA.IApplicationModule)
                thisTypedInstance.Initialise()
                m_addonInstances.Add(thisInstance)
            Next
        End If

Putting it all together, our console application should begin to look something like so:

Imports System.Reflection

Module Module1

    Private m_addonInstances As New List(Of ClassLibA.IApplicationModule)

    Sub Main()
        LoadAdditionalModules()

        Console.WriteLine('Finished loading modules ...')
        Console.ReadLine()
    End Sub

    Private Sub LoadAdditionalModules()
        Dim currentApplicationDirectory As String = My.Application.Info.DirectoryPath
        Dim addonsRootDirectory As String = currentApplicationDirectory & '\Addons\'
        Dim addonsLoaded As New List(Of System.Type)

        If My.Computer.FileSystem.DirectoryExists(addonsRootDirectory) Then
            Dim dllFilesFound = My.Computer.FileSystem.GetFiles(addonsRootDirectory, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dll")
            For Each dllFile In dllFilesFound
                Dim modulesFound = TryLoadAssemblyReference(dllFile)
                addonsLoaded.AddRange(modulesFound)
            Next
        End If

        If addonsLoaded.Count > 0 Then
            For Each addonToInstantiate In addonsLoaded
                Dim thisInstance = Activator.CreateInstance(addonToInstantiate)
                Dim thisTypedInstance = CType(thisInstance, ClassLibA.IApplicationModule)
                thisTypedInstance.Initialise()
                m_addonInstances.Add(thisInstance)
            Next
        End If
    End Sub

    Private Function TryLoadAssemblyReference(ByVal dllFilePath As String) As List(Of System.Type)
        Dim loadedAssembly As Assembly
        Dim listOfModules As New List(Of System.Type)
        Try
            loadedAssembly = Assembly.LoadFile(dllFilePath)            
        Catch ex As Exception
        End Try
        If loadedAssembly IsNot Nothing Then
            For Each assemblyModule In loadedAssembly.GetModules
                For Each moduleType In assemblyModule.GetTypes()
                    For Each interfaceImplemented In moduleType.GetInterfaces()
                        If interfaceImplemented.FullName = 'ClassLibA.IApplicationModule' Then
                            listOfModules.Add(moduleType)
                        End If
                    Next
                Next
            Next
        End If
        Return listOfModules
    End Function
End Module

Trial Run

At this point we should be able to perform a full build of our solution. When your files have been built, copy the compiled assembly output of the AddonA project into the Addons folder of ConsoleAppA. The Addons folder should be created under the /bin/debug/ folder. On my machine using Visual Studio 2010, default project locations and a solution called “DotNetAddons” the folder is here:

C:\Users\jplenderleith\Documents\Visual Studio 2010\Projects\DotNetAddons\ConsoleAppA\bin\Debug\Addons

We should see the following output when we run the code is run:

MyAddonClass is starting up ...
Finished loading modules ...

As it stands it’s not flashy or impressive but it does demonstrate a key piece of functionality, namely that at runtime we can pick up an assembly and execute code within that assembly without having any existing knowledge about that assembly. This is the foundation of building more complex add-ons.


Step 3 – Integrating with a User Interface

Next, we’ll take a look at building a couple of add-ons to provide additional functionality within a Windows Forms application.

Similar to the existing solution, create a new solution with the following projects:

  • WinFormsAppA: A Windows Forms application
  • ClassLibA: A class library
  • UIAddonA: A class library that will house a couple of add-ons with UI components

Similar to our previous solution, both the WinFormsAppA and UIAddonA projects should have references to the ClassLibA. The UIAddonA project will also need a reference to the System.Windows.Forms for access to functionality.

The Windows Forms Application

We’ll make a quick and simple UI for our application consisting of a MenuStrip and a DataGridView. The MenuStrip control should have three MenuItems

  • File
  • Add-ons
  • Help

Dock the DataGridView to its parent container – the form itself. We’ll put together some code to display some mock data in our grid. The Add-ons MenuItem will be populated by any add-ons that have been loaded on application start-up.

Here’s a screenshot of the application at this point:

Let’s write some code to give the main form of WinFormsAppA some functionality. When the form loads it’ll call the LoadAddons() method which is currently empty – we’ll fill that in later. Then we generate some sample employee data to which we bind our DataGridView.

Public Class Form1

    Private m_testDataSource As DataSet
    Private m_graphicalAddons As List(Of System.Type)

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        LoadAddons()
        m_testDataSource = GenerateTestDataSet()
        With DataGridView1
            .AutoGenerateColumns = True
            .AutoResizeColumns()
            .DataSource = m_testDataSource.Tables(0)
        End With
    End Sub

    Private Sub LoadAddons()        

    End Sub

    Private Function GenerateTestDataSet() As DataSet
        Dim newDataSet As New DataSet
        Dim newDataTable As New DataTable
        Dim firstNames = {"Mary", "John", "Paul", "Justyna", "Michelle", "Andrew", "Michael"}
        Dim lastNames = {"O'Reilly", "Murphy", "Simons", "Kelly", "Gates", "Power"}
        Dim deptNames = {"Marketing", "Sales", "Technical", "Secretarial", "Security"}

        With newDataTable
            .Columns.Add("EmployeeId", GetType(Integer))
            .Columns.Add("Name", GetType(String))
            .Columns.Add("IsManager", GetType(Boolean))
            .Columns.Add("Department", GetType(String))
        End With

        For i = 1 To 100
            Dim newDataRow As DataRow = newDataTable.NewRow()
            With newDataRow
                .Item("EmployeeId") = i
                .Item("Name") = firstNames(i Mod firstNames.Count) & " " & lastNames(i Mod lastNames.Count)
                .Item("IsManager") = ((i Mod 20) = 0)
                .Item("Department") = deptNames(i Mod deptNames.Count)
            End With
            newDataTable.Rows.Add(newDataRow)
        Next

        newDataSet.Tables.Add(newDataTable)
        Return newDataSet
    End Function

End Class

When we run the application it should look like so:

We’ll come back to our empty LoadAddons() after we’ve defined the add-on interfaces.

Add-on Interface

Let’s define our add-on interface. UI components will be listed under the Add-ons MenuStrip, and will open up a windows form that has access to the data to which our DataGrid is bound. To the ClassLibA project add a new interface file called IGraphicalAddon and paste in the following code into the file:

Public Interface IGraphicalAddon

    ReadOnly Property Name As String
    WriteOnly Property DataSource As DataSet
    Sub OnClick(ByVal sender As Object, ByVal e As System.EventArgs)

End Interface
  • We have a Name property, which is pretty self-explanatory.
  • The DataSource properly is used to ‘feed’ data to this add-on.
  • The OnClick method, which will be used as the handler when users click on our add-on’s entry in the Addons menu.

Loading the Add-ons

Add a class library called AddonLoader to the ClassLibA assembly project, with the following code:

Imports System.Reflection

Public Class AddonLoader
    Public Enum AddonType
        IGraphicalAddon = 10
        ISomeOtherAddonType2 = 20
        ISomeOtherAddonType3 = 30
    End Enum

    Public Function GetAddonsByType(ByVal addonType As AddonType) As List(Of System.Type)
        Dim currentApplicationDirectory As String = My.Application.Info.DirectoryPath
        Dim addonsRootDirectory As String = currentApplicationDirectory & "\Addons\"
        Dim loadedAssembly As Assembly
        Dim listOfModules As New List(Of System.Type)

        If My.Computer.FileSystem.DirectoryExists(addonsRootDirectory) Then
            Dim dllFilesFound = My.Computer.FileSystem.GetFiles(addonsRootDirectory, Microsoft.VisualBasic.FileIO.SearchOption.SearchAllSubDirectories, "*.dll")
            For Each dllFile In dllFilesFound

                Try
                    loadedAssembly = Assembly.LoadFile(dllFile)
                Catch ex As Exception
                End Try
                If loadedAssembly IsNot Nothing Then
                    For Each assemblyModule In loadedAssembly.GetModules
                        For Each moduleType In assemblyModule.GetTypes()
                            For Each interfaceImplemented In moduleType.GetInterfaces()
                                If interfaceImplemented.Name = addonType.ToString Then
                                    listOfModules.Add(moduleType)
                                End If
                            Next
                        Next
                    Next
                End If

            Next
        End If

        Return listOfModules
    End Function
End Class

You could use code similar to this to restrict add-on developers to build only specific types of add-ons

In this class, we’ve provided a way to load different types of add-ons. You could use code similar to this to restrict add-on developers to build only specific types of add-ons, or to at least categorise them. In our example, we’ll just be using the first add-on type declared, namely IGraphicalAddon.

If we had other add-on types in our project, for example to enhance reporting functionality or provide some useful keyboard shortcuts, then we don’t want them listed in our Add-ons menu, as there’s no point in someone being able to click on that add-on.

Having said that though, it may be desirable to add a reference to all add-ons under some menubar, click on which would cause the add-on’s options form to be displayed. This however is beyond of the scope of this tutorial.

The Graphical Add-on

Let’s build the actual UI add-on. To the UIAddonA assembly project add the following two files; a class called UIReportAddon1 and a windows form called UIReportAddon1Form. The UIReportAddon1 class will contain the following code:

Imports ClassLibA

Public Class UIReportAddon1
    Implements ClassLibA.IGraphicalAddon

    Private _dataSource As DataSet
    Public WriteOnly Property DataSource As System.Data.DataSet Implements IGraphicalAddon.DataSource
        Set(ByVal value As System.Data.DataSet)
            _dataSource = value
        End Set
    End Property

    Public ReadOnly Property Name As String Implements IGraphicalAddon.Name
        Get
            Return "Managers Report"
        End Get
    End Property

    Public Sub OnClick(ByVal sender As Object, ByVal e As System.EventArgs) Implements IGraphicalAddon.OnClick
        Dim newUiReportingAddonForm As New UIReportAddon1Form
        newUiReportingAddonForm.SetData(_dataSource)
        newUiReportingAddonForm.ShowDialog()
    End Sub
End Class

To UIReportAddon1Form add a DataGridView that’s docked within its parent container. Then add the following code:

Public Class UIReportAddon1Form

    Private m_providedDataSource As DataSet

    Public Sub SetData(ByVal DataSource As System.Data.DataSet)
        m_providedDataSource = DataSource
        FilterAndShowData()
    End Sub

    Private Sub FilterAndShowData()
        Dim managers = m_providedDataSource.Tables(0).Select("IsManager = True")
        Dim newDataTable = m_providedDataSource.Tables(0).Clone
        For Each dr In managers
            newDataTable.ImportRow(dr)
        Next
        DataGridView1.DataSource = newDataTable
    End Sub

    Private Sub UIReportAddon1Form_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Text = "List of managers"
    End Sub
End Class

We’re simply providing the means to send data to the form, and then let it decide what to do with said data. In this case, we’re going to perform a Select() on a DataTable, retrieving back a list of all employees who are managers.

Back to our Main UI

Now it’s time to complete our unfinished LoadAddons() method in our WinFormsAppA project. This code will instruct the GetAddonsByType method of ClassLibA.AddonLoader to find a particular type of add-on – in this case IGraphicalAddon add-ons.

For each add-on found, the following actions are performed

  • Create a new instance of the add-on
  • Type the add-on instance to IGraphicalAddon
  • Populate its DataSource property
  • Add the add-on to the Add-ons menu item
  • Add a handler for that menu item’s Click event
    Private Sub LoadAddons()
        Dim loader As New ClassLibA.AddonLoader
        Dim addonsLoaded = loader.GetAddonsByType(ClassLibA.AddonLoader.AddonType.IGraphicalAddon)

        For Each graphicalAddon In addonsLoaded
            Dim thisInstance = Activator.CreateInstance(graphicalAddon)
            Dim typedAddon = CType(thisInstance, ClassLibA.IGraphicalAddon)
            typedAddon.DataSource = m_testDataSource
            Dim newlyAddedToolstripItem = AddonsToolStripMenuItem.DropDownItems.Add(typedAddon.Name)
            AddHandler newlyAddedToolstripItem.Click, AddressOf typedAddon.OnClick
        Next
    End Sub
    

Testing our UI

Ensure you can perform a full successful compile of the solution. Copy the UIAddonA.dll from the output debug folder of the UIAddonA project into the /bin/debug/Addons/ folder of the WinFormsAppA project. When you run the project, you should see a grid of data, as before. If you click into the Add-ons menu however you should now see a reference to the newly created add-on.

When we click on the Managers Report menu item, this will case a method call to the OnClick method implemented in our add-on, which will cause UIReportAddon1Form to appear, as below.


Wrap Up

We’ve seen two examples of building an application which can pickup and run add-ons as required. As I mentioned earlier, it should be easy enough to integrate this type of functionality into existing applications. The question of how much control you’ll need (or want) to give third party developers is another matter entirely.

I hope you had fun with this tutorial! Thank you so much for reading!

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://readwriteweb.com.br Diego Gomes

    I love when you talk about .NET

    There’s an app for monitoring .NET apps that i’m in love with. Check it out: Deskmetrics.com

  • http://sasa.po.gs sasa

    why not in C#?

  • http://www.freshclickmedia.com/blog Shane

    Interesting article. Although I know some people prefer VB.NET, I find C# so much easier to read.

    However, my main point is that you haven’t made the example relevant to the web.

  • Jeff

    Although I like to see .net articles on the site, i am not sure I really like this one. The author didn’t really make it relevant to the web, and it really isn’t a example that anyone should be following. It really isn’t so simple to deal with addons in this matter. What about updating an addon (dealing with the appdomain). For this matter why not have just shown how to wire up MEF.

    As far as web goes (this is nettuts after all). Asp.net MVC areas give you better addon style functionality that what you have here. And you could do some interesting things with the app_code directory.

    Anyhow, I hope you do keep up with .net tutorials, but keep a greater eye out for relevance and quality.

  • Rob Henry

    Shane’s got a good point, but I do love .NET articles from NetTuts (specifically VB.NET, but I can usually translate C#)…

    Either way, I walked through the steps and it crashed when pulling up the Managers Report. I found the cause was in the Form1.vb file. The Form1_Load Sub has the following lines:

    LoadAddons()
    m_testDataSource = GenerateTestDataSet()

    It causes it to crash because the m_testDataSource variable is Nothing when it is being passed to the AddOns. The two lines need to be switched.

    Good article, I thought, but maybe a followup article on how this approach can be best used on the web.

  • Jeff

    Although I am glad to see another .net tutorial, you should have really keep it related to the web. Plus this really insn’t the best way to do things (especially for the web).

    Asp.net MVC gives you areas, which if setup properly you could create modular (extensable) websites just creating and removing areas.

    Then there is always MEF witch can handle, finding your addons, and composing your parts, as well as allowing for some sort of recomposission.

    Anyhow, maybe you plan on doing a followup with how to set this up for the web, but there are already libraries in the .net framwork that help out with these things.

  • http://www.dazzlecat.co.uk DazzleCat Digital Agency

    Surely this should’ve been provided in C#.

    Seriously, does anyone still use vb.net?

    • http://www.hsp.dk Henrik Pedersen

      Come on, please don’t start a war… The language doesn’t matter, it’s the programmers skills and ability to create an efficient solution.. C# and VB are identical at performance (because of the CLR) and they can do pretty much the same…

      So please, move along everybody – Nothing here :)

    • Selcuk

      Seriously, are you not able to translate it to C#? Seriously?

      Thank you for this article btw.

  • Dan F

    @Jamie MEF’d be a better choice for loading the addins. http://mef.codeplex.com/ – It’s baked into the framework and works with Silverlight and MVC, which’d give this article a nice web spin.

    @vb haters – herp derp. That’s about as much sense as you’re making. It’s just a language. You should be thanking the author for sharing some knowledge rather than moaning about their language choice.

  • http://alanfeekery.com Alan Feekery

    Really needed to be in C#.

  • Stimul8d

    For all the VB.Net haters out there…Get over it!!

    Ultimately, if you’re a pro .Net dev then you’ll eventually have to support or maintain a VB.Net application. I can’t count how many companies I’ve worked for that have moved from VB 6 or earlier to VB.Net thinking things will be the same but better. THIS IS NOT THE CASE and it’s why VB gets such a bad rep.

    Other than a few odd differences the languages are comparable with each other and having worked with both since the pre 1.1 days there are still some features of VB that make me jealous as a C# lover. Take a look at some of these answers on StackOverflow – http://stackoverflow.com/questions/158229/what-are-the-pros-of-vb-net

    I do agree that MEF is probably preferred here. However, we rely too much on frameworks to do everything for us now. Ultimately this is a tutorial based on what functionally must be done to achieve a plugin engine for your apps and I’ve written this code or very similar in lots of different apps before MEF cam about. Also, MEF is not just a plugin framework and you’d probably have to get involved with Dependency Injection and Inversion Of Control to give a good tut on MEF which isn’t the point of the tut.

    ….Should’ve been web based though I guess. Hey maybe you could knock up a quick DesktopTuts.com for us guys? :-)

    • http://www.hsp.dk Henrik Pedersen

      Seriously, listen to the guy… I know you primary focus is on “the web” and so, but you already have graphics, videos, sound/music, Flash, html/php/css covered. Why not take the step and go to desktop developement? I would LOVE to see some tutorials on that topic, and I think many others would too.

      And it is actually quite relevant, many times I’ve been asked to do some sort of “desktop client” for some sort of website, one way or another. So desktop-development is quite relevant.

      By the way, would LOVE to see some sort of chat tutorial, but not the usual “make it look good and easy” more like something a more high performance or something. Sometimes I really think there is a little to much “designer” on this site and not so much hard coding.

      Both are good, but there are so many people visiting this site. Please don’t make them all focus on design and code like crap ;)

    • Jeff

      Well .net in and of itself is a framework, so no getting around not using frameworks with .net :). But in all seriousness MEF handles things really nice and for the purpose of this tutorial it would have needed any other DI or IOC stuff. MEF is just a set of tools that helps make these task easier. Just like when the added generics, and lambdas, and linq. Sure there was a time when I wrote this code as well, but the question I have is would you still write it or would you use MEF or something.

      I don’t have a problem with doing it yourself, but at least talk about MEF and then say why you might want to not use it. since it is baked right in.

      I am only saying this because if you were new to .net you might look at the tutorial and say, “What the hell, why do I have to write my own code to discover and compose my own addins”. When the truth is you don’t have to. You can just create the app and say you need and addin, create you addin, and away you go.

      Even with MEF you might end up rolling out your own for some reason (like maybe for some reason you don’t like having to attribute all your classes). But at least let people now, hey if you don’t want to build it yourself, this functionality already exists in .net especially when you are saying that the tutorial is a .net 4 tutorial and MEF was put in .net 4 to basically do exactly what he is doing here.

      Anyhow, I think enough people have mentioned it in the comments now though, so people reading the article should be able to go look it up.

  • http://mokshasolutions.com Moksha

    Its really nice to see a advance .net tutorial. please keep it up and let more .net tutorial coming.

    thanks

  • David

    So after everything that has been said, any of you hardcore .net developers want to put your money where your mouth is and do a tutorial on MEF. An answer of “google it” or “look on MSDN” is not acceptable.

    • Jeff

      A MEF tutorial would be fun, I would give it a go if there is interest. Question is would they publish it :). On the web side depending on what type of modularity you are looking for you might not even need MEF, possibly just using the areas feature in ASP.NET MVC 3. That might be fun as well, build out an MVC 3 site with areas, and then show how to get even more addon style functionality with MEF.

      Maybe I will start brainstorming a little on what would make for a good example project to build a tutorial on.

      • http://midnightprogrammer.net Prashant

        I agree with Jeff. A tutorial on MEF with C# NOT VB would be great. MEF is great and as far as implementation is concerned is far more easy than the above code.

  • http://www.ifc0nfig.com Paul

    I’d like to see the plug-ins being loading in to their own AppDomain so if a plug-in crashes then it doesn’t take down the “host” app.

    • Jeff

      Olivine in there own AppDomain has always been kind of the problematic thing with .net. The system.addons namespace I believe was designed to try to handle this type of thing. But it wasn’t entirely simple to implement.

      It souls make for a pretty lengthy tutorial, but again it would be very interesting.

  • Roberto

    I stopped reading as soon as I saw visual basic code, C# is the unofficial industry standard for .net, vb is so verbose it’s hard to read.

  • devvvy

    Hi

    One question – is it impossible to safe guard an application hosting third party dll?

    See this thread, even if third party dll loaded into separate AppDomain, it can still access AppDomain.Current.Get/SetData

    In addition to AppDomain.Current.Get/SetData, can third party examine application memory. For example, hosting application may contain a secret/private key in some application context, which is used to decrypt communications or licensing file. Even if private key is not placed in AppDomain.Current.Get/SetData, is it possible for third party dll to … perhaps “reflect” on the process memory foot print and extract the private key?

    If the answer is yes – then it follows really the moment you load a third party dll into your own process, you cannot be sure if your process has been compromised?

    I think security is even more important than say process isolation safe guarding against crashes in third party dll.

    Thanks

    NOTE: This is NOT a question on CAS (Code Access Security) as setting permissions/evidence doesn’t has anything to do with access to AppDomain from third party dll

    Also, this is not a question on serializing access to a singleton instance object

    http://www.codeproject.com/Messages/3794309/How-do-you-protect-your-app-hosting-third-party-dl.aspx

  • HarryMay

    I was just curious as to how I go about changing my password on here? Couldn’t find it when I did a quick scan, thanks.

  • Noobs

    VB is for Gay noobs!

  • http://www.google.co.uk bob

    The article is good. The language of choice if fine. Its the knowledge you need to learn not the syntax. Be grateful and stfu about vb…

  • Marco

    Absolutely great article, however I’m implementing it somewhat differently. Instead of a form starting up, I have a base application that has an icon in the system tray to start off with, with only an Exit option. I want to create addons for it, however what I want to do is add context menu items to the existing menu, and then have the addons contain what sub-items are going to be added (and ofcourse have events for those).

    I can easily add the initial items for each addon, however I am stumped as to how to add sub-items! Can anybody assist?

  • Androidz

    i got an error message on sub loadaddons For each graphicaladdon in addonsloaded it says, it is does not declared. Now, I’m confused what to declare of data type is grahphicaladdon be.