Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Create Strongly Typed Swappable Class Libraries

0.00/5 (No votes)
15 Jan 2008 1  
Create a strongly typed system for plugging in interchangeable class libraries (DLLs), without having multiple versions of your main application.

The Problem

It was decided by the powers that we take an existing in-house application and release it externally. This application used a proprietary class library, which could not to be included. However, the application would need the same functionality in a new class library when released externally. Furthermore, the existing in-house class library was scheduled to be re-architected in the near future.

The challenge was to maintain a single code base for the application to support both the existing and the new DLLs, and be flexible enough to support the yet-to-be-designed rewrite of the existing DLL. This seemed a perfect scenario to use the System.Reflection namespace and the GetInterface() method. This would allow me to create swappable class libraries for each implementation option, and access them in a type safe manner.

The Solution

The plan was to create an interface to describe the properties, methods, and events that will be exposed from the external class library. Any external dynamic linked library must implement this interface. We will then create a helper class library implementing the same interface. The helper class library will contain all the logic needed to load an external DLL implementing the interface. The main application will simply link to the helper class library, and remain oblivious to the logic needed to link specific external class libraries.

We will use VB.NET 2005 to create a solution of several fairly generic projects. These projects will serve no useful purpose other than to demonstrate this concept. The first thing we need to do is create an interface that describes our swappable library. We will create a class library project named InterfaceDLL. This project contains a single interface named ILibrary.

Public Interface ILibrary
    Function GetName() As String
End Interface

This interface states that any DLL to which our application intends to link must expose a GetName() function that returns a String data type. It is important to notice that we created a separate project for the interface. This is because the fully qualified name of the interface includes the project namespace. When other projects refer to this interface, they will refer to <InterfaceDLL.>ILibrary. If we just linked the interface across projects, it would still belong to the individual projects, and thus, not be the same interface.

Next, we will create the first class library to use this interface. This will be the RedDLL project. It will contain the following code.

Imports InterfaceDLL
Public Class clsMe
    Implements ILibrary
    Public Function GetName() As String Implements ILibrary.GetName
        Return "RedDLL"
    End Function
End Class

This code imports the InterfaceDLL namespace, and instructs this class to implement the ILibrary interface. All we are required to implement is the GetName() function. Here, we are returning the library name, “RedDLL”. We will create a nearly duplicate BlueDLL project, using the same interface. In our test case, it is the same code, with the exception of returning “BlueDLL”. It is included in the sample solution.

Next, we will create the helper class library project, in this case, ColorDLL. This project contains all the .NET magic for this example. First, just like the previous two class libraries, this one imports the InterfaceDLL, and exposes the GetName() function. But, this function is a little different from the others. This one makes use of the System.Reflection namespace that we have imported. We can use LoadFrom() from that namespace to get the assembly from a given class library (specified, in this case, in the app.config). We will then wade through the assembly, looking for an object that implements the ILibrary interface. When we find it, we call its GetName() function.

Imports InterfaceDLL
Imports System.Reflection
Public Class clsMe
    Implements ILibrary
    ' Grab the name from main application's app.config
    Private strColorDLL As String = _
        System.Configuration.ConfigurationSettings.AppSettings("ColorDLL")

    Public Function GetName() As String Implements ILibrary.GetName
        Dim objAssembly As Reflection.Assembly
        Dim clsColor As ILibrary = Nothing
        ' We're assuming the library is in the bin directory for this application
        Dim strColorDLLPath As String = _
            System.IO.Path.Combine(My.Application.Info.DirectoryPath, strColorDLL)
        Dim objTypes() As Type
        Dim objFound As Type
        Dim strRV As String = String.Empty

        ' Load the assembly from the DLL
        objAssembly = Reflection.Assembly.LoadFrom(strColorDLLPath)
        ' March through the types in the assembly
        objTypes = objAssembly.GetTypes
        For Each objItem As Type In objTypes
            ' Looking for our Interface
            objFound = objItem.GetInterface("ILibrary")
            If objFound IsNot Nothing Then
                ' We wouldn't be here if it wasn't the right type, so we can DirectCast
                clsColor = DirectCast(objAssembly.CreateInstance(objItem.FullName), _
                    ILibrary)
                Exit For
            End If
        Next
        ' If we've got it, call our function
        If clsColor IsNot Nothing Then
            strRV = clsColor.GetName
        End If
        ' Let 'em have it
        GetName = strRV
    End Function
End Class

For each project containing a class importing the ILibrary interface, you will need to add a project reference to the InterfaceDLL project. This is done by opening the References tab in My Project, and clicking the Add button. Open the Projects tab in the Add Reference form, and find the InterfaceDLL project.

Finally, we will create the main application project, in this case, creatively named MainExe. For this example, we will just drop the code into the Load event for Form1.

Public Class Form1
    Dim clsColor As New ColorDLL.clsMe

    Private Sub Form1_Load(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles MyBase.Load
        Me.lblLibrary.Text = clsColor.GetName
    End Sub
End Class

Form1_Load() simply calls the GetName() function from the helper class. MainExe knows nothing of the internals of RedDLL or BlueDLL, and doesn’t care. As long as RedDLL and BlueDLL implement the ILibrary interface, the helper library will quietly call them.

Now, a couple things are happening behind the scenes here. First, when the developer builds the MainExe project, a reference will have to be added to the appropriate RedDLL or BlueDLL project or DLL, as well as a reference to the helper class. Additionally, we will add a line to the app.config to specify which DLL will be loaded by the helper class library. Remember, the app.config key is referenced in the helper class library, ColorDLL. It is not referenced in the main application.

<appSettings>
    <!--It is assumed that the library is in the bin directory, 
        we only need its name-->
    <add key="ColorDLL" value="BlueDLL.dll"/>
</appSettings>

Conclusion

Now, using this method, you can create a system for plugging in interchangeable libraries, without having multiple versions of your main application. You are also ready for future libraries that implement the same interface. Finally, you do not have to stray from your type safe development.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here