Assembly compatibility verification.

Started by
14 comments, last by Earthmark 11 years, 1 month ago

I am currently attempting to make a project modular using the managed extension framework, however it allows third party mods where the plugin might not be designed for the current project version.

Backwards compatibility fixes a lot of this, however I need a way to tell if there is some of the plugins are incompatible, and then remove that plugin before attempting to import the needed data.

This also can't be done one on one, as if one plugin requires another, and together they would work, but testing independently shows them as missing a link.

So, I currently need a way to verify if a set of assemblies can work properly, and prune out any that are incompatible.

Advertisement

if you change your interface from one version to the other, the plugins that use the old interface won't load. at least they shouldn't.

if you're really that worried, you can always create an attribute that describes for what version of your project the plugin is made, and exige that each plugin uses that attribute on the assembly, then on load you check if that version is still compatible.

you can use the same approach for plugins that require another, but they really should use MEF features to do that...

anyway, it seens that 2 simple attributes can solve your problem, they don't even need code, you can just check if they are present.

The issue is if you do an update that does not change the interface then the plugin will be rejected for a different version number. Currently with MEF when you try to import information it will throw an exception if one of the assemblies are not compatible (aka some interface changed), so I am trying to find out how it is doing that check and do it manually.

Otherwise that would mean you would need to keep an attribute for every interface version, and that seems like a large overhead to throw onto plugin makers and hard to keep updated to start with.

Also as I understand it, one could try each plugin one at a time as assemblies can't do circular references (at least visual studio yells when you try).

have you tried the update that does not change the interface? because MEF shouldn't refuse to load based on this...

unless...

is your interface defined on the same assembly that uses it? i would advise to move it to a different assembly, an API. this way, you only update that assembly when you do make a update that changes the interface.

as for the attribute method, you can use it as follows:


 [CompatibleWith(Version=1.0)] 
public class Component : IComponent 
{ 
... 
}
 

then in your project, you can store with is the earlyest version that is still compatible and use that version to check.

you can combine the 2 methods (the API assembly and the attribute) to load only parts of a plugin that are compatible with your current version.

you also can write you custom "MEF" to do the loading, then you can apply more filters and advanced options on the loading stage, you basically just search for assemblies and use reflection to load them, if you do choose this path, i can help you.

sadly i'm at work, otherwise i could upload a sample...

anyway, keep me informed in your progress and i'll help the most i can, this is a subject that i really like biggrin.png

As it stands MEF only has issues if an interface (or reference of any kind) changed and was used in the plugin, if you change a system that is unrelated but inside the main assembly it has no issues (Yay for versioning). However for this reason some plugins will be compatible as long as the api sections that the plugin uses don't change.

So just saying it is compatible with a specific version would not work entirely when it could also work with future versions depending on if there are api changes to specific systems.


If this was to be implemented for every possible interface though, you would be checking every possible link, meaning in large plugins there could be hundreds of these attributes, and the assembly size would increase dramatically. As well as it would become a nightmare for plugin makers to keep track of the version numbers for every reference.

Also I am not sure about this, but I was under the impression linking had to occur before you could traverse the assembly, so it would crash before this point from a missing reference or mismatched reference.

As it stands MEF only has issues if an interface (or reference of any kind) changed and was used in the plugin, if you change a system that is unrelated but inside the main assembly it has no issues (Yay for versioning). However for this reason some plugins will be compatible as long as the api sections that the plugin uses don't change.

So just saying it is compatible with a specific version would not work entirely when it could also work with future versions depending on if there are api changes to specific systems.


i see, i think i was misunderstanding you, you are worried that a new version of your project may change behavior that the plugin expects, without changing something that the plugin direct uses...

i don't think there's any automated way you can use to ensure that unless you force a recompile of the plugin for each new version (assuming each recompile comes with tests...)

i think that the only way to ensure that everything works just right is to update the plugin every time the main application updates, there's not much more to do...

The each method should have the same behavior as defined in the documentation, so that changing over versions should not be an issue.

The issue is currently if any assembly loaded from mef does not link properly (a reference changed) the whole things thrown an exception and denies loading. I just want to check if the assemblies work (as in linking was successful) and if it was not successful then remove the problematic assemblies and try again.

i think i found a way to do something like what you want in this post:

http://msdn.microsoft.com/en-us/magazine/ee291628.aspx

look for the section "Diagnosing Rejection", is that what you need?

Not really, the issue is not the importer itself it is that an exception is being thrown as the dll is linked, before the objects are imported.

Example of the exception


System.Reflection.ReflectionTypeLoadException was unhandled
  HResult=-2146232830
  Message=Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.


[LoaderExceptions information, specific names removed and replaced with <t>]
{System.TypeLoadException: Could not load type '<class name>' from assembly '<Assembly name>, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.}


The issue also only happens when the CompositionContainer attempts to import data.

I think I found a way around it, seems like getting all of the types inside an assembly will force checking.

Current code, wish it didn't involve exceptions:


var dlls = new List<Assembly>(dllNames.Select(Assembly.LoadFile));

foreach (var assem in dlls)
{
	try
	{
		assem.GetTypes();
	}
	catch (ReflectionTypeLoadException e)
	{
		dlls.Remove(assem);
	}
}

This topic is closed to new replies.

Advertisement