6

I am writing an Addin Framework in C# and I'm wondering how I can make Addin's unloadable without requiring a restart of the application.

I heard of AppDomains but how do these work? Can an Addin add extendability classes and be called in the Main AppDomain by Interfaces and still be unloadable and call cleanup code resulting in those classes being removed without that Assembly being in the Main AppDomain?

Or are there other methods of achieving unloadable addins, but IIRC other then AppDomain's you cannot unload an Assembly.

I also want the addin engine to be compatible with Mono if possible, so any answers try to stay compatible with Mono, if you can.

cdiggins
  • 17,602
  • 7
  • 105
  • 102
DrHouse
  • 99
  • 1
  • 8
  • why do you write an extra framework? there are a lot of "out-of-the-box" solutions, e.g. you could use MEF http://msdn.microsoft.com/library/ee332203.aspx (or any other mono-compatible ioc which can register/ungregister contexts). See http://www.mono-project.com/Compatibility and the release notes. – Beachwalker Jan 28 '12 at 13:19
  • See also http://stackoverflow.com/questions/14278/how-to-load-plugins-in-net/14185590. – cdiggins Jan 06 '13 at 19:06

3 Answers3

7

You might want to look at Mono.Addins. There are some good looking samples here, Here are some of the details:.

The following code is a basic example of an add-in host application. This application runs a set of commands which can be implemented by add-ins:

using System;
using Mono.Addins;

[assembly:AddinRoot ("HelloWorld", "1.0")]

class MainClass
{
    public static void Main ()
    {
        AddinManager.Initialize ();
        AddinManager.Registry.Update ();

        foreach (ICommand cmd in AddinManager.GetExtensionObjects<ICommand> ())
            cmd.Run ();
    }
}

The extension point for the above example can be declared like this:

using Mono.Addins;

[TypeExtensionPoint]
public interface ICommand
{
    void Run ();
}

An add-in extending the above extension point would look like this:

using System;
using Mono.Addins;

[assembly:Addin]
[assembly:AddinDependency ("HelloWorld", "1.0")]

[Extension]
public class HelloCommand: ICommand
{
    public void Run ()
    {
        Console.WriteLine ("Hello World!");
    }
}
IanNorton
  • 7,145
  • 2
  • 25
  • 28
  • +1 and thanks for that I didn't know about that facility. What's the .Registry since it's mono it's not 'the registry' at least not always. – kenny Jan 28 '12 at 13:51
  • I Always thought Mono.Addins was just based off the tech used from SharpDevelop for MonoDevelop, never knew it was a completely different system. This could work for my idea in programs with some extra additions so this ill accept as an answer. I like the fact you can even disable addons on the fly, only wish you could completely unload, but due to limitations of .NET, i guess that's impossible. – DrHouse Jan 28 '12 at 20:07
  • 1
    Mono has a registry interface, it all gets treated the same way it does on .Net, on linux the "registry" interface is backed by small config files, on windows by the real registry. In this case though "Registry" is a different thing. – IanNorton Jan 29 '12 at 09:44
4

Dynamically Loading Plug-ins / Add-ins

You didn't explicitly ask how to dynamically load add-in or plug-ins, but you can see this question (and my answer) on StackOverflow.com on how to do so.

Unloading Plug-ins and Add-ins

There is only one way that I am aware of to unload dynamically loaded plug-ins and add-ins: by loading the add-in in a separate AppDomain and unloading the AppDomain. For more information see this article on MSDN.

Existing Add-in / Plug-in Frameworks

Why reinvent something that already exists? I know of two plug-in frameworks.

Some people talk about the Managed Extensibility Framework (MEF) as a plug-in or add-in framework, which it isn't. For more information see this StackOverflow.com question and this StackOverflow.com question.

Community
  • 1
  • 1
cdiggins
  • 17,602
  • 7
  • 105
  • 102
0

There are two parts to "unloading" an add-in.

  1. Unregister the addin so it is not "connected" to your program (it is not hooked up to any events, holding any resource locks, is not needed by or called by the main program at any time, and is not actively running any code).

  2. Unload the assembly containing the addin code.

The first part is entirely in your control - if your addin subscribes to an event, then when you ask it to shut down it must unsubscribe. If your program creates buttons and menu items for the addin, then it must know about them and be able to remove them when the addin shuts down. etc.

It is up to you to decide whether the addin is responsible for this (in which case a rogue addin could take down the entire application if it doesn't clean up properly), or whether the addin framework must provide mechanisms for connecting to the main application so that it is able to clean up all the links between the app and addin automatically (i.e. run the addin in a safer "sandbox" where it is less able to adversely affect the stability of the application or other addins).

Once the addin is shut down it becomes totally dormant, and then it will be safe to unload it. (However, unless you want to be able to update the addin dll while the program is running, you may find you don't even need to unload the addin - simply disabling it may achieve your needs)

Jason Williams
  • 56,972
  • 11
  • 108
  • 137
  • I'm also trying to understand AppDomains, as thats how you can unload Assemblies. How would one communicate between them? – DrHouse Jan 28 '12 at 08:42
  • You cannot communicate directly between AppDomains, but you can communicate via WCF for example. – dwonisch Jan 28 '12 at 09:34