# Assembly compatibility verification.

This topic is 1782 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

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.

Edited by Earthmark

##### Share on other sites

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.

##### Share on other sites

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).

##### Share on other sites

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.

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

##### Share on other sites

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.

##### Share on other sites

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...

##### Share on other sites

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.

Edited by Earthmark

##### Share on other sites

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?

##### Share on other sites

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

[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.

Edited by Earthmark

##### Share on other sites

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();
}
{
dlls.Remove(assem);
}
}


##### Share on other sites

not sure how this code works, the foreach loop should throw an InvalidOperationException, as you modify the collection on the loop...

the problem i can see is that this will load the assembly in your appDomain, maybe you want to create another, so you can unload them after?

also, shouldn't it be a List ? it seens that you're trying to load multiple assemblies from one file...

maybe this method can help in a first attempt to removo possible problematic assemblies:

http://msdn.microsoft.com/en-us/library/system.reflection.assembly.getreferencedassemblies.aspx

using it, you can check if the assembly references your own, then you can check the version it references, if it's lower than the current one, you remove it. this way you'll not have an exception.

at this point i'm just throwing suggestions on the table, but maybe we can get something that works for you, my current understanding is that you're receiving an exception everytime you load an plugin that was compiled with an old version of your main project, that isn't compatible anymore...

this question on StackOverflow has an example use of the method i described:

http://stackoverflow.com/a/2135347

i really couldn't find a way to only skip the assembly if it isn't compatible, as in "if it uses an older version, but is still compatible, load it", all solutions i found are either based on version numbers or in type loader exceptions...

##### Share on other sites

The issue is not that the assembly is missing references, it finds and links them when it is loaded. The issue is that a reference inside both assemblies is a mismatch.

Also yes that code crashes, better fix that quickly.

So it is like it is loading the assembly as a side object then testing if it works. If it does then it will be loaded to an AggregateCatalog for MEF. This also removes the need for the dlls object:

var catalog = new AggregateCatalog();
{
try
{
assem.GetTypes();
}
{
}
}


Also the issue is that it is wanted that even of the plugin was designed for an older version it will still run, provided there are no reference errors. That way if plugin makers don't need to update they don't have to. It saves time for the plugin maker and for users that don't have to update every plugin with each new release. Hence why excluding based on version numbers can't really tell if there is even an issue.

##### Share on other sites
well, what is strange is that i just tested and it seens like there's no problem if i change the host application as long as i don't change the interfaces used by the plugin... on the case that the interface changes, then there's no way to run the plugin without a recompile... how are you loading your plugins? i tested with the DirectoryCatalog and it worked fine. in the case i change the interface, this is the message i get: {"Method '' in type '' from assembly 'plugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.":""} it's not the same you're getting, so i supose it happens under another circunstance? anyway, your solution seens to be the only way to do this, as a look into the MEF documentation doesn't reveal anything useful for that... and if the GetTypes method throws an exception, i don't think you can do much more. i'll keep looking and if i found a better solution i'll let you know, your problem may as well be mine, as i'll use MEF on the same way on my next project

##### Share on other sites

I used to use a DirectoryCatalog however it does not allow the type of checking above; In the current project it still uses one actually , I haven't had time to implement any updates. Also the assembly I was using to test had massive differences (method renaming, some properties were removed, explicit implementation of things that don't exist in the interface anymore) between the interfaces, so that is probably why I had a different error.

Also thank you for the help, and I hope your next project does not have as many issues  as this one is having.

##### Share on other sites

i'll probably have the same issues

yeah, in the case of massive changes, your solution is the only working one until now, it's a shame that MEF doesn't current have that kind of hook, i'm thinking that i should create my own implementation for it...

##### Share on other sites

the issue is that MS doesn't have a TryLoadFile() or something like that, you can know it does the check as it throws the exception but I can't find a method or construct that can just return if the check was successful.

Edited by Earthmark

##### Share on other sites

This topic is 1782 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Create an account

Register a new account