Ok no problem ... In the attribute I gave you I would define the role of the
plugin (multiple vs single) this would allow you to key off it in your
generic factory (you could also force it to be a singleton if you saw fit).
For interface type things you could even define them via plugin name in your
config file (i.e. friendly names instead of class names).
Make sure to put your interfaces / plugin required data types in a separate
assembly (this way 3rd parties can just reference this .dll instead of your
actual assemblies). Another benefit of this is your public contracts to the
plugins are all isolated making it much easier to maintain.
For maintaining plugins (loading etc) the methodology I use now is to put
them in a directory tree ... Then I call a function like ...
#region LoadPluginDirectoryTree
public void LoadPluginDirectoryTree(string _Path) {
if(!System.IO.Directory.Exists(_Path)) {
throw new System.IO.DirectoryNotFoundException("Source folder '" + _Path +
"' not found");
}
try {
string [] DirList = System.IO.Directory.GetDirectories(_Path);
foreach(string DirEntry in DirList) {
LoadPluginDirectoryTree(DirEntry) ;
}
string [] FileList = System.IO.Directory.GetFiles(_Path);
foreach(string CurrentFile in FileList) {
try {
this.LoadAssembly(CurrentFile) ;
}
catch (Exception Ex) {
//we should raise an event some day
throw Ex;
}
}
}
catch(Exception Ex) {
throw Ex;
}
}
#endregion
This will recurse through the directory tree loading the assemblies ... This
is an "unlazy" load which can take a few seconds but because I am building
up indexes for the types inside of loadassembly it is lightening fast for
retrieval.
Hope this helps you out,
Greg
-----Original Message-----
From: Gary James [mailto:ga***@iotech.com]
Sent: Friday, June 18, 2004 1:50 PM
To: Greg Young
Subject: Re: References for designing a "Plug-In" software architecture
Greg,
Whew ... now that's a response!!!
To answer your questions;
(1) I envision the need for two types of plugins. TypeA would be a single
use plugin; that is, only one plugin of multiple TypeA plugins can run at a
time. An example of this would be to provide the program with multiple GUI
interfaces., each tailored for a specific niche application. The main
program would be configured to start and load the specified application
interface. The TypeB plugin would provide optional services and
functionality to the application. This model would be similar in concept to
the one employed by video codecs. The presence of the plugin means that it
can be instantiated and used alone, or in concert with others. Examples of
this would be different plugins that provide different views, or methods of
processing data. I prefer the design to be modular with only one plugin
per assembly. This would isolate code and make regression testing simpler
following maintenance cycles. Also, multiple developers can be working on
multiple plugins.
(2) The plugins will be local only. They will be released as part of a CD
software installation, with newer versions or additions available on CD or
FTP download.
If you have any other suggestions I'd really like to hear them. Thanks.
Gary ...
"Greg Young" <gr********@planetbeach.com> wrote in message
news:%2****************@TK2MSFTNGP12.phx.gbl...
doing an interface based plugin system is remarkably easy ...
a few questions though...
1) do you want to isolate the plugins ? i.e. seperate appdomains
2) are the plugins to be local or do they need to be capable of being
distributed objects ?
the simplest route for plugins providing you don't want either of the
above
is just to run through an assembly getting the types ... you can then
run through the interfaces that the type supports .. supporting
inheritance chains as well is not very difficult. You would then up
with a factory method that you pass in a type to ... it would return
the objects in the assemblies you told it to look in (i.e. a
subdirectory). You could also strongly type these factories by
subclassing specific plugin factories ...
I
would also recommend lazy loading this info and hitting a cache the
second time through as it can be slow to get this info (esp with debug
symbols).
slightly modified example (only loads plugins with attribute but loads
them
for all interfaces they support) ...
public void LoadAssembly(string _AssemblyPath) {
Assembly PluginAssembly;
try {
PluginAssembly = Assembly.LoadFrom(_AssemblyPath) ;
}
catch (Exception Ex) {
throw new System.Exception("Unable to load assembly " +
_AssemblyPath,
Ex) ;
}
//have assembly get all types.
System.Type [] AssemblyTypes = PluginAssembly.GetTypes() ;
Type [] Interfaces ;
foreach(Type CurrentType in AssemblyTypes) {
object [] attributes = CurrentType.GetCustomAttributes(false);
foreach(object CurAttr in attributes) {
if(CurAttr is PluginAttribute) {
Console.WriteLine("Found plugin " + CurrentType.FullName);
Console.WriteLine(((PluginAttribute)CurAttr).Name +
((PluginAttribute)CurAttr).Description);
Interfaces = CurrentType.GetInterfaces() ;
foreach(Type foo in Interfaces) {
Console.WriteLine("Interface of " + foo.ToString());
}
PluginEntry p = new PluginEntry();
p.AssemblyPath = _AssemblyPath ;
p.Type = CurrentType ;
p.Interfaces = Interfaces ;
//at this point we have all the info add it
PluginEntries.Add(p) ;
break;
}
}
}
Console.Write("Loaded " + AssemblyTypes.Length + " objects.\n");
}
Once you have the types you would just use CreateInstance to create
them.
I would also recommend using an optional custom attribute on your
plugins
so
you can optionally give them a friendlyname, description, etc.
Example:
[AttributeUsage(AttributeTargets.Class,Inherited=fa lse,AllowMultiple=false)]
public class PluginAttribute : Attribute {
private string m_Name;
private string m_Description;
public PluginAttribute(string _Name, string _Description) {
this.m_Name = _Name ;
this.m_Description = _Description ;
}
public string Name {
get {
return m_Name;
}
}
public string Description {
get {
return m_Description;
}
}
}
Maintaining plugins in a seperate app domain has benefits but
complicates things a bit. Let me know if you need info on that.
Hope this helps ya a bit.
Greg
"Gary James" <ga***@iotech.com> wrote in message
news:ea**************@tk2msftngp13.phx.gbl...
This may not be a direct C# question, but since I'll be using using
C#
for
development, I thought I'd pose the question here.
I'll soon be involved in the design of a new software product that will
employ a software "Plug-In" architecture. Taking the plug-in route
will
give us a design that can adapt to, as yet, undefined future
requirements
(within the scope of the plug-in interface spec of course). In the
past
I've done this with COM components that register themselves in a list of
available code resources. However, I'd be interested to hear how any
of
you have approached the design for a software plug-in architecture,
and/or
any references you may have used to make your design decision.
Gary ...
"Gary James" <ga***@iotech.com> wrote in message
news:eu**************@TK2MSFTNGP09.phx.gbl...
Greg,
Whew ... now that's a response!!!
To answer your questions;
(1) I envision the need for two types of plugins. TypeA would be a single
use plugin; that is, only one plugin of multiple TypeA plugins can run at
a time. An example of this would be to provide the program with multiple
GUI interfaces., each tailored for a specific niche application. The main
program would be configured to start and load the specified application
interface. The TypeB plugin would provide optional services and
functionality to the application. This model would be similar in concept
to the one employed by video codecs. The presence of the plugin means that
it can be instantiated and used alone, or in concert with others. Examples
of this would be different plugins that provide different views, or methods
of processing data. I prefer the design to be modular with only one plugin
per assembly. This would isolate code and make regression testing
simpler following maintenance cycles. Also, multiple developers can be working
on multiple plugins.
(2) The plugins will be local only. They will be released as part of a
CD software installation, with newer versions or additions available on CD or
FTP download.
If you have any other suggestions I'd really like to hear them. Thanks.
Gary ...
"Greg Young" <gr********@planetbeach.com> wrote in message
news:%2****************@TK2MSFTNGP12.phx.gbl... doing an interface based plugin system is remarkably easy ...
a few questions though...
1) do you want to isolate the plugins ? i.e. seperate appdomains
2) are the plugins to be local or do they need to be capable of being
distributed objects ?
the simplest route for plugins providing you don't want either of the above is just to run through an assembly getting the types ... you can then
run through the interfaces that the type supports .. supporting inheritance
chains as well is not very difficult. You would then up with a factory
method that you pass in a type to ... it would return the objects in the
assemblies you told it to look in (i.e. a subdirectory). You could also
strongly type these factories by subclassing specific plugin factories
.... I would also recommend lazy loading this info and hitting a cache the
second time through as it can be slow to get this info (esp with debug
symbols).
slightly modified example (only loads plugins with attribute but loads
them for all interfaces they support) ...
public void LoadAssembly(string _AssemblyPath) {
Assembly PluginAssembly;
try {
PluginAssembly = Assembly.LoadFrom(_AssemblyPath) ;
}
catch (Exception Ex) {
throw new System.Exception("Unable to load assembly " +
_AssemblyPath, Ex) ;
}
//have assembly get all types.
System.Type [] AssemblyTypes = PluginAssembly.GetTypes() ;
Type [] Interfaces ;
foreach(Type CurrentType in AssemblyTypes) {
object [] attributes = CurrentType.GetCustomAttributes(false);
foreach(object CurAttr in attributes) {
if(CurAttr is PluginAttribute) {
Console.WriteLine("Found plugin " + CurrentType.FullName);
Console.WriteLine(((PluginAttribute)CurAttr).Name +
((PluginAttribute)CurAttr).Description);
Interfaces = CurrentType.GetInterfaces() ;
foreach(Type foo in Interfaces) {
Console.WriteLine("Interface of " + foo.ToString());
}
PluginEntry p = new PluginEntry();
p.AssemblyPath = _AssemblyPath ;
p.Type = CurrentType ;
p.Interfaces = Interfaces ;
//at this point we have all the info add it
PluginEntries.Add(p) ;
break;
}
}
}
Console.Write("Loaded " + AssemblyTypes.Length + " objects.\n");
}
Once you have the types you would just use CreateInstance to create
them.
I would also recommend using an optional custom attribute on your
plugins so you can optionally give them a friendlyname, description, etc.
Example:
[AttributeUsage(AttributeTargets.Class,Inherited=fa lse,AllowMultiple=false
)] public class PluginAttribute : Attribute {
private string m_Name;
private string m_Description;
public PluginAttribute(string _Name, string _Description) {
this.m_Name = _Name ;
this.m_Description = _Description ;
}
public string Name {
get {
return m_Name;
}
}
public string Description {
get {
return m_Description;
}
}
}
Maintaining plugins in a seperate app domain has benefits but
complicates things a bit. Let me know if you need info on that.
Hope this helps ya a bit.
Greg
"Gary James" <ga***@iotech.com> wrote in message
news:ea**************@tk2msftngp13.phx.gbl... This may not be a direct C# question, but since I'll be using using C#
for development, I thought I'd pose the question here.
I'll soon be involved in the design of a new software product that
will employ a software "Plug-In" architecture. Taking the plug-in route will give us a design that can adapt to, as yet, undefined future requirements (within the scope of the plug-in interface spec of course). In the past I've done this with COM components that register themselves in a list
of available code resources. However, I'd be interested to hear how any of you have approached the design for a software plug-in architecture, and/or any references you may have used to make your design decision.
Gary ...