Writing C# Plugin System

Writing C# Plugin System

It sounds like you have a circular reference. You said your plugins reference Lab.Core.DLL, but you also say the plugins are loaded from Lab.Core.DLL.

Am I misunderstanding what is happening here?

EDIT: OK now that you have added your question to the question...

You need to have Lab.Core.DLL accessible to the plugin being loaded since it is a dependency. Normally that would mean having it in the same directory or in the GAC.

I suspect there are deeper design issues at play here, but this is your immediate problem.

System with plugins in C#

There are a huge number of ad-hoc plug-in systems for C#. One is described in Plugin Architecture using C# (at The Code Project). The general approach is that the host application publishes an assembly with interfaces. It enumerates through a folder and finds assemblies that define a class that implement its interfaces and loads them and instantiates the classes.

In practice you want to do more. It's best if the host application defines two interfaces, an IHost and an IPlugIn. The IHost interface provides services that a plug-in can subscribe to. The IPlugIn gets constructed taking an IHost.

To load a plug-in, you should do more than simply get a plug-in. You should enumerate all plug-ins that are loadable. Construct them each. Ask them if they can run. Ask them to export APIs into the host. Ask them to import APIs from the host. Plug-ins should be able to ask about the existence of other plug-ins.

This way, plug-ins can extend the application by offering more APIs.

PlugIns should include events. This way plug-ins can monitor the process of plug-ins loading and unloading.

At the end of the world, you should warn plug-ins that they're going to go away. Then take them out.

This will leave you with an application that can be written in a tiny framework and implemented entirely in plug-ins if you want it to.

As an added bonus, you should also make it so that in the plug-ins folder, you resolve shortcuts to plug-ins. This lets you write your application and deliver it to someone else. They can author a plug-in in their development environment, create a shortcut to it in the application's plug-ins folder and not have to worry about deploying after each compile.

Writing an Addin or Plugin Framework in C#

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!");
}
}

C# plugin system design

The Managed Extensibility Framework is designed for plugin architectures. Before you go too far down your current path, check it out. It might serve you better.

Application plugin system

Have a look at the Orchard project on Codeplex. The Microsoft developers have build a plugin mechanism similar to what you are describing. Its pretty complex stuff...

Best way to create a plugin environment in .NET

"so much better" always depends on your point of view and requirements. If your approach fits your needs, go for it. But plugins can become very fast much more complicated. What about dependencies between plugins? Security? Different schemata how to find plugins? ...? Those kind of features are already solved for you. If you don't need them, a library might be overkill. If you need them, it would be a bad idea to reinvent the wheel. ;-)

C# COM Plugin System

Ok I was able to answer it myself. To Explain what was wrong. What I did to may help\improve others work in future.

I turned on the FusionLog in the Registry and on the LoaderException I checked for the FusionLog

catch (ReflectionTypeLoadException ex)
{
StringBuilder sb = new StringBuilder();
foreach (Exception exSub in ex.LoaderExceptions)
{
sb.AppendLine(exSub.Message);
FileNotFoundException exFileNotFound = exSub as FileNotFoundException;
if (exFileNotFound != null)
{
if (!string.IsNullOrEmpty(exFileNotFound.FusionLog))
{
sb.AppendLine("Fusion Log:");
sb.AppendLine(exFileNotFound.FusionLog);
}
}
sb.AppendLine();
}
pluginError = sb.ToString();
}

After enabling the FisonLog on the Registry (HKLM\SOFTWARE\Microsoft\Fusion!EnableLog (DWORD 1) I was able to see that the missing DLL is actually needed at the location of the executing program that call's the OLEObject to create an instance of the system via COM.

I wasn't aware of this, but yeah in some way it's rather logic. Luckily i didn't messed up anything on the code it was just in the wrong place.

Plugin based application in C#

To implement a plugin interface manually, you will need a method something like this. I've left some TODOs in, where you would want to enhance the error handling and/or make the implementation a little more case specific.

    public List<T> LoadPlugin<T>(string directory)
{
Type interfaceType = typeof(T);
List<T> implementations = new List<T>();

//TODO: perform checks to ensure type is valid

foreach (var file in System.IO.Directory.GetFiles(directory))
{
//TODO: add proper file handling here and limit files to check
//try/catch added in place of ensure files are not .dll
try
{
foreach (var type in System.Reflection.Assembly.LoadFile(file).GetTypes())
{
if (interfaceType.IsAssignableFrom(type) && interfaceType != type)
{
//found class that implements interface
//TODO: perform additional checks to ensure any
//requirements not specified in interface
//ex: ensure type is a class, check for default constructor, etc
T instance = (T)Activator.CreateInstance(type);
implementations.Add(instance);
}
}
}
catch { }
}

return implementations;
}

Example to call:

List<IPlugin> plugins = LoadPlugin<IPlugin>(path);

As for the c++ part of your question. There are few different ways you could approach this, though the correct choice depends on your specific situation. You can make a clr compliant .dll in c++, which your c# project could reference and call like any other .dll it references. Additionally, you could use P/Invoke to call into a native .dll.

Write a program that accepts plug-ins

It's absolutely possible. There are different ways of doing it.

One way is to create an interface, eg IPlugin which may have an init (setup, register plugin etc), execute (run command, pass parameters, return value), and unload method.

Alternatively you could have a PluginAttribute you could put on your class/method to tell the C# app it is a plugin.

The app could use reflection and find plugin classes in the assembly.



Related Topics



Leave a reply



Submit