Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I hot swap referenced DLL's without recompiling the Solution in VS2008?

Our solution has a reference to a DLL which is used to communicate to some hardware over Ethernet. We have created a 2nd DLL which can be used to simulate the hardware, so that our developers do not need said hardware at each of their desks.

The software should not know if it is using real hardware or the simulator. How can we swap the references without needing to recompile the solution?

Can we just name both references the same and simply register/unregister the correct DLL that we want to reference?

[Update] Note: The first DLL is a 3rd party DLL that we do not have access too. The 2nd DLL was created by us in C++. Our application is written in C#.

like image 582
Ryan R Avatar asked May 18 '11 22:05

Ryan R


2 Answers

Make both DLL's implement a common interface (ICommunicateToYourHardware) and code the application to discover the DLL via reflection rather than by reference.

Per Request adding sample

The interface in this example is called IAuthenticate, but you can use any interface in it's place. In this case I am actually looking for any number of IAuthenticate classes. In your case if the different DLLs are placed in the same relative path the same compilation will pull in the different DLLs.

 // We need a container for the DLL files that we find and then a container for the instances of 
    // the plug ins created from the dlls. In this test we are only really looking for One such plug in
    // but I prefer to use collections for such things as it allows for a more scalable design. This technique
    // works for 1, 100, or more plugins and/or methods.
    private List<string> _DLLS;
    private List<iAuthenticate> _PlugIns;

    private int LoadPlugIns(string Path)
    {
        /// Within the designated Path (and in all subdirectories) locate all .dll files and put the path 
        /// to these files in a collection.
        GetDLLS(Path);
        foreach (string dirName in Directory.GetDirectories(Path))
        {
            LoadPlugIns(dirName);
        }

        // For each .dll file, inspect it (using reflection) to determine if it is of the iAuthenticate Type
        // if it is, create and instance of the object and store it in a collection, and assign a delegate to 
        // invoke its Authenticate method from the host application.
        foreach (string DLL in _DLLS)

        {
            Assembly myAssembly = Assembly.LoadFrom(DLL);
            Type[] Types = myAssembly.GetTypes();
            foreach (Type myType in Types)
            {
                Type T = myType.GetInterface("iAuthenticate");
               if (T != null)
                {
                    if (_PlugIns == null) { _PlugIns = new List<iAuthenticate>(); }
                    _PlugIns.Add((iAuthenticate)myAssembly.CreateInstance(myType.FullName));
                }
            }
            foreach (iAuthenticate iAuth in _PlugIns)
            {
                this.Authorize += iAuth.Authenticate;
            }
        }
        return _PlugIns.Count;
   }

    private void GetDLLS(string Path)
    {
        if (_DLLS == null){_DLLS = new List<string>();}
        foreach (string filename in Directory.GetFiles(Path, "*.dll")) 
        {
            _DLLS.Add(filename);
        }
    }

once we have the reference set via reflection we can invoke its methods like this:

    private void btnLogon_Click(object sender, EventArgs e)
    {
        try
        {
            if (Authorize.Invoke(txtUsername.Text, txtPassword.Text, txtPath.Text))
            {
                this.BackgroundImage = TelefloraDemo.Properties.Resources._189469;
                this.pnlLogon.Visible = false;
                MessageBox.Show("You have Logged On!");
            }
        }
        catch (AuthenticationException aex)
        {
            DemoCode.LogException(aex);
            MessageBox.Show(aex.ToString());
        }
        catch (Exception ex)
        {
            DemoCode.LogException(ex);
            MessageBox.Show("No Authenticator");
        }

    }

    public delegate bool Authenticate(string Username,string Password,string Path);
    public event Authenticate Authorize;

Now, obviously your mileage may vary, but this should get you on a successful track. (Yes, there are other ways, I like this one..)

like image 71
Cos Callis Avatar answered Oct 16 '22 18:10

Cos Callis


MEF (Managed Extensibility Framework) makes it really easy to do this sort of thing. Just make sure your real and mock interfaces export the same contract and use MEF composition to have the desired version injected.

here is a simple example of how to use it.

like image 35
Yaur Avatar answered Oct 16 '22 19:10

Yaur