|
I had the same requirements for my app. It's basically a job manager where each plugin does a specific maintenance task. It runs nearly constantly but does support "hot swapping" plug-in .DLL's if they are running with Shadow Copy support.
I initially looked at MAF and pretty much spit my drink all over the monitor while looking at the documentation.
I then went and found The Simple Plugins Framework[^] out on SourceForge (yeah, I know...) and found it did just about everything I needed out of the box, including ShadowCopy support and automatic AppDomain load and unload.
The code hasn't been updated in about 5 years now but it worked brilliantly. I had to tweak it a little bit to get everything I needed but that was simple to do.
And I'm even using log4net between the plugins and the job manager. It required coming up with a custom appender that supported marshalling log events between AppDomains but that was pretty easy to find.
|
|
|
|
|
Dave Kreskowiak wrote: I then went and found The Simple Plugins Framework[^] out on SourceForge (yeah, I know...) and found it did just about everything I needed out of the box, including ShadowCopy support and automatic AppDomain load and unload.
Thanks for that. That looks much easier to use than MAF.
".45 ACP - because shooting twice is just silly" - JSOP, 2010
- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
Dave Kreskowiak wrote: The Simple Plugins Framework[^] Me like!
Thanks!
#SupportHeForShe
Government can give you nothing but what it takes from somebody else. A government big enough to give you everything you want is big enough to take everything you've got, including your freedom.-Ezra Taft Benson
You must accept 1 of 2 basic premises: Either we are alone in the universe or we are not alone. Either way, the implications are staggering!-Wernher von Braun
|
|
|
|
|
I like it.
I may do a fork of it on Github when my computer gets back (likely within the first two weeks of next month).
What do you get when you cross a joke with a rhetorical question?
The metaphorical solid rear-end expulsions have impacted the metaphorical motorized bladed rotating air movement mechanism.
Do questions with multiple question marks annoy you???
|
|
|
|
|
So I got home and downloaded the DLL (I should have GOTTEN the source as well).
When I got to work, sourceforge is blocked (as is github). I can't find any examples anywhere of anyone that's using this. :/
".45 ACP - because shooting twice is just silly" - JSOP, 2010
- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
I ALWAYS get the for source for anything I use like this. I even picked up the source for Irony when I used that too.
Anyway, the only thing I used to get this running was this[^].
I'm on vacation as of today and all my code using this project is at work.
|
|
|
|
|
Well, like I said, sourceforge is blocked here at work. It would really help if the simpleplugins code implemented intellisense comments... It ain't that hard to do, and there are very few public components.
In any case, I have to wait until I get home to get the source and get a copy of the html page that shows how to use the library.
Do you know of any other web resources other than sourceforge?
".45 ACP - because shooting twice is just silly" - JSOP, 2010
- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
The source of SourceForge has an example application in it, so that helped.
The only other example I know of is a GitHub (because of course it is), here[^]
How about this to get you started:
First, the pluggable application.
1. Open your pluggable application project in Visual Studio.
2. Add a reference to the SimplePlugins.dll from your project.
3. Add using/imports directives where you would like to initialize and use the plugin loader provided by the library like so,
using SimplePlugins;
using SimplePlugins.Exceptions;
4. Initialize the PluginLoader object like so,
this.PluginLoader = new PluginLoader();
5. You can specify additional paths where plugin dependencies will be located like so,
this.PluginLoader.AssemblyResolutionPaths.Add(Application.StartupPath);
6. You can make the plugin loader use the .Net framework’s shadow copy option when loading assemblies like so, (You can further customize the cache path, etc by handling the PluginLoader.PluginLoading event)
this.PluginLoader.ShadowCopyEnabled = true;
7. You can then hook up to the several events which enable the pluggable application to manage plugin behavior like so,
this.PluginLoader.ProbeComplete += new PluginLoaderBase.ProbeCompleteEventHandler(PluginLoader_ProbeComplete);
this.PluginLoader.PluginLoading += new PluginLoaderBase.PluginLoadingEventHandler(PluginLoader_PluginLoading);
this.PluginLoader.PluginLoaded += new PluginLoaderBase.PluginLoadedEventHandler(PluginLoader_PluginLoaded);
this.PluginLoader.PluginUnloaded += new PluginLoaderBase.PluginUnloadedEventHandler(PluginLoader_PluginUnloaded);
8. You can probe available plugins from a location in the hard disk as follows, The PluginLoader.Probe method scans the specified directory and subdirectories for valid plugin assemblies and returns a list.
PluginInfoList pluginInfoList = this.PluginLoader.Probe("C:\plugins", SearchOption.AllDirectories);
for (int i = 0; i < pluginInfoList.Count; i++)
lbPlugins.Items.Add(pluginInfoList[i]);
9. Use the PluginLoader.Load method to execute any of the plugins returned by the PluginLoader.Probe method above. Parameters can also be passed to the plugin using the PluginParameters class. Any unhandled exceptions which may occur during the loading process is wrapped by the serializable PluginException class and rethrown to make sure no AppDomain leakages occur. Hence the try-catch block.
PluginInfo template = (PluginInfo)lbPlugins.SelectedItem;
try
{
PluginParameters args = new PluginParameters();
args.Add("Param1", "The quick brown fox jumped over the lazy dog");
args.Add("Param2", 100);
args.Add("Param3", 7.321);
this.PluginLoader.Load(template.FileName, args);
}
catch (PluginException ex)
{
Console.WriteException(ex);
}
10. You may use the PluginLoader.NotifyUnload or PluginLoader.NotifyUnloadAll methods to notify a plugin that it needs to be unloaded.
11. You can use the PluginLoader.PluginUnloaded event to check whether plugins executed successfully and their return values as follows.
void PluginLoader_PluginUnloaded(object sender, PluginLoaderBase.PluginUnloadedEventArgs e)
{
if (e.Results.UnhandledException != null)
Console.WriteException("The plugin '" + e.Info.ToString() + "' was unloaded due to unhandled exception: " + e.Results.UnhandledException.ToString());
else if (e.Results.ExecutionDenied)
{
if (e.Info.ExecutionMode == PluginBase.ExecutionModes.AsynchronousExclusive || e.Info.ExecutionMode == PluginBase.ExecutionModes.SynchronousExclusive)
Console.WriteInfo("The plugin '" + e.Info.ToString() + "' was unloaded since it is intended to be executed exclusively. Please make sure no other plugin is executing and try again.");
else if (e.Info.ExecutionMode == PluginBase.ExecutionModes.AsynchronousSingleton || e.Info.ExecutionMode == PluginBase.ExecutionModes.SynchronousSingleton)
Console.WriteInfo("The plugin '" + e.Info.ToString() + "' was unloaded since only one instance of it is intended to be executed at a time. Please make sure no other instance of the same plugin is executing and try again.");
else
Console.WriteInfo("The plugin '" + e.Info.ToString() + "' was unloaded.");
}
else
{
if (e.Results.Contains("ReturnValue"))
Console.WriteInfo("The plugin '" + e.Info.ToString() + "' was unloaded successfully with the return value: " + Convert.ToString(e.Results.Get("ReturnValue")));
else
Console.WriteInfo("The plugin '" + e.Info.ToString() + "' was unloaded successfully");
}
}
That’s it! You have got yourself a pluggable application. Now you can write a plugin by following the steps below.
1. Open or create a project for the plugin in Visual Studio. This can be an executable type project or a class library project.
2. Add a reference to the SimplePlugins.dll.
3. Add a class under any name which will represent the plugin. Derive this class from the PluginBase abstract class provided by the Simple Plugins library and override its methods appropriately. Place your main processing code inside the Main method. The Main method is called by the PluginLoader.Load method after the plugin is successfully loaded.
using SimplePlugins;
using SimplePlugins.Exceptions;
namespace SamplePluggableApp.SamplePlugin
{
public class Plugin : PluginBase
{
public Plugin()
: base()
{
}
internal string Param1 { get; private set; }
internal int Param2 { get; private set; }
internal double Param3 { get; private set; }
public override string FriendlyName
{
get { return "Sample Plugin"; }
}
public override ExecutionModes ExecutionMode
{
get { return ExecutionModes.AsynchronousMultiInstance; }
}
public override PluginParameters Main(PluginParameters args)
{
this.Param1 = (string)args.Get("Param1");
this.Param2 = (int)args.Get("Param2");
this.Param3 = (double)args.Get("Param3");
MainView pluginForm = new MainView();
pluginForm.Show();
Application.Run(pluginForm);
args.Add("ReturnValue", "Success");
return args;
}
public override void OnUnloadNotification()
{
Application.Exit();
}
}
}
That’s all there is to it. Place the output of your plugin project in the plugins folder path and let Simple Plugins do everything else for you. If the functionality provided by the standard PluginLoader and PluginBase classes are not enough, you can extend those classes to meet your own needs. You may refer the code on how the default PluginLoader class is implemented to get an idea about writing a custom loader.
|
|
|
|
|
thanks for that.
".45 ACP - because shooting twice is just silly" - JSOP, 2010
- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
Well, that didn't do me a lot of good. I still have to go home and unblock the dll (or bring the source code to work) because our group policy doesn't allow us to unblock a remote dll.
I hate where I work...
I'm off to do other crap...
".45 ACP - because shooting twice is just silly" - JSOP, 2010
- You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
- When you pry the gun from my cold dead hands, be careful - the barrel will be very hot. - JSOP, 2013
|
|
|
|
|
Well, I can't do anything about that. Sorry.
|
|
|
|
|
Just write something that is so complex they have to cart you off to the funny farm...just for sh*ts and giggles of course.
Stop talking to me, I'm not talking to you, then who is talking to me. Why won't the voices stop!
|
|
|
|
|
Visual Studio 2015 is totally MEF based, 2012 and 2013 is as well, I think. Just saying... For good or bad
|
|
|
|
|
I'm gonna pray for those around you.
|
|
|
|
|
"Maf" is actually the Dutch word for "weird"
|
|
|
|
|
Given the sheer amount of guns and ammo you do possess, I pray for those around you.
|
|
|
|
|
If a chicken crosses the road, is that poultry in motion?
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
Bootiful!
I wanna be a eunuchs developer! Pass me a bread knife!
|
|
|
|
|
|
Just as long as it stays abreast of the oncoming Mac truck!
Marc
|
|
|
|
|
It's Big that truck - thank you for that Nugget of information!
Bad command or file name. Bad, bad command! Sit! Stay! Staaaay...
|
|
|
|
|
Feather you realize it or not, that's a lot of crop to peck through and consider.
Ravings en masse^ |
---|
"The difference between genius and stupidity is that genius has its limits." - Albert Einstein | "If you are searching for perfection in others, then you seek disappointment. If you are seek perfection in yourself, then you will find failure." - Balboos HaGadol Mar 2010 |
|
|
|
|
|
I want to live in a world where a chicken can cross the road without its motives being questioned.
|
|
|
|
|
it's a free chicken
|
|
|
|
|
You get a good one, so are you going to crow about it.
Mongo: Mongo only pawn... in game of life.
|
|
|
|