Register Plugins class from another assembly than PluginBase and use IsAssignableFrom
In our project, the base class for the plugins are located in another project. Looking at the code, the PluginManager seems to only look for classes within the assembly itself (basePluginType.Assembly).
private void RegisterPlugins(IEnumerable<Type> basePluginTypes, Dictionary<string, EntityMetadata> metadata, List<MetaPlugin> plugins, Dictionary<EventOperation, Dictionary<ExecutionStage, List<PluginTrigger>>> register)
{
foreach (var basePluginType in basePluginTypes)
{
if (basePluginType == null) continue;
Assembly proxyTypeAssembly = basePluginType.Assembly;
foreach (var type in proxyTypeAssembly.GetLoadableTypes())
{
if (type.BaseType != basePluginType) continue;
RegisterPlugin(type, metadata, plugins, register);
}
}
SortAllLists(register);
}
Futhermore, our Plugins have multiple inheritence layers, causing type.BaseType not to be sufficient. Is it possible to change RegisterPlugins to use IsAssignableFrom instead?
Sounds like quite a project structure, but I think we can solve it in a good way.
There is a problem with using IsAssignableFrom, since it will return all classes in your inheritance layer. Given that we can't assume all inherited classes are abstract, there is no trivial solution to this problem. One would have to figure out how to only return the final layer of inheritance.
So here is my solution. Since XrmMockup can take multiple plugin base types I would like you to add the base classes for all your plugins there. This would ensure the correct base classes are checked. If this does not include all the assemblies you need, then I suggests we add a new optional setting to XrmMockup additionalPluginAssemblies which the pluginManager can use to find your plugins.
Does that sound reasonable to you?
Hi Magnus, I took a look at the code, and I don't get a clear understanding why you need the basetypes to register the plugins in th PluginManager. Because in the method RegisterPlugins, the argument 'plugins' is given. In fact in that list, all plugins to be registered are already present. I saw that in the AssemblyName property of the MetaPlugin, actually the typename of the plugin is stored, not the assemblyname. If both typename and assemblyname would be present as properties of MetaPlugin, it should be easy to get the TypeInfo of each plugin, and compare it to the basePluginTypes
The base type is used to filter classes. When you provide base classes it gives XrmMockup something to match against. By giving the direct base class you ensure me that all classes that extend that base class are to be treated as plugins. This is not true if we use IsAssignableFrom, since there can be multiple base classes.
I don't understand your comment about MetaPlugin and AssemblyName, can you elaborate? Perhaps with an example?
Hi Magnus,
Here I have a code sample how the method PluginManager.RegisterPlugins could be adjusted without the need for the basetype. See comment in code that MetaPlugin needs some adjustment
private void RegisterPlugins(IEnumerable<Type> basePluginTypes, Dictionary<string, EntityMetadata> metadata, List<MetaPlugin> plugins, Dictionary<EventOperation, Dictionary<ExecutionStage, List<PluginTrigger>>> register) { //foreach (var basePluginType in basePluginTypes) //{ // if (basePluginType == null) continue; // Assembly proxyTypeAssembly = basePluginType.Assembly;
// foreach (var type in proxyTypeAssembly.GetLoadableTypes())
// {
// if (type.BaseType != basePluginType) continue;
// RegisterPlugin(type, metadata, plugins, register);
// }
//}
// In fact in plugins parameter all information is already provided to register the plugins,
// without the need of baseType.
// Seems however that in MetaPlugin.AssemblyName, the type's fullname is stored.
// MetaPlugin type should be changed that both AssemblyName and TypeName are stored
// For now, make the assumption that the assemblyname is the same as the type's namespace
var pluginTypeNames = plugins.Select(x => x.AssemblyName).Distinct().ToArray();
var pluginNames = pluginTypeNames
.Select(x => new
{
AssemblyName = x.Substring(0, x.LastIndexOf('.')),
TypeName = x
})
.ToArray();
foreach (var item in pluginNames)
{
try
{
Assembly asm = Assembly.Load(item.AssemblyName);
Type pluginType = asm.GetType(item.TypeName);
RegisterPlugin(pluginType, metadata, plugins, register);
}
catch (Exception ex)
{
// do nothing for now
}
}
SortAllLists(register);
}
Met vriendelijke groet / Kind regards,
Harm Neervens
Senior IT Architect Software Delivery Center Information Technology Division Europe PACCAR / DAF Trucks N.V.
' +31 (0)40 214 3457 • [email protected]mailto:[email protected]
CONFIDENTIALITY NOTICE: This e-mail and any attachments, files or previous e-mail messages attached to it may contain confidential information and is for the intended recipient(s) only. Confidential information should not be disclosed, copied, distributed or used without the permission of the sender or PACCAR. If you are not the intended recipient, please notify me by reply e-mail and destroy the original transmission.
From: Magnus Gether Sørensen [email protected] Sent: Friday, June 29, 2018 9:14 AM To: delegateas/XrmMockup [email protected] Cc: Harm Neervens [email protected]; Comment [email protected] Subject: Re: [delegateas/XrmMockup] Register Plugins class from another assembly than PluginBase and use IsAssignableFrom (#62)
The base type is used to filter classes. When you provide base classes it gives XrmMockup something to match against. By giving the direct base class you ensure me that all classes that extend that base class are to be treated as plugins. This is not true if we use IsAssignableFrom, since there can be multiple base classes.
I don't understand your comment about MetaPlugin and AssemblyName, can you elaborate? Perhaps with an example?
— You are receiving this because you commented. Reply to this email directly, view it on GitHubhttps://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fdelegateas%2FXrmMockup%2Fissues%2F62%23issuecomment-401269098&data=02%7C01%7Charm.neervens%40daftrucks.com%7C028e7fb5038740c4c4e908d5dd8fdcd4%7Ce201abf9c5a343f88e29135d4fe67e6b%7C0%7C0%7C636658532308503976&sdata=l2bs2ZJ%2F%2BrY2BPcbyhFwQ2ck6YzTGa3zn3nBK40Vwlg%3D&reserved=0, or mute the threadhttps://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fgithub.com%2Fnotifications%2Funsubscribe-auth%2FAmv4FQWY9ufLDc3r9YDWzDIs6vLbNSCmks5uBdOtgaJpZM4U5gv1&data=02%7C01%7Charm.neervens%40daftrucks.com%7C028e7fb5038740c4c4e908d5dd8fdcd4%7Ce201abf9c5a343f88e29135d4fe67e6b%7C0%7C0%7C636658532308503976&sdata=%2FdX41pWTbZPTTTyc9v6CXM0Rs0kKE%2F7WSfzeR2%2F7jsY%3D&reserved=0.
If it helps, I have a pending pull request (ExternalLibraries) that implements loading external plugins and custom workflows from libraries in a given path. It's in a fork if anyone wants access now