Jump to content

  • Log In with Google      Sign In   
  • Create Account

Assembly compatibility verification.


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
15 replies to this topic

#1 Earthmark   Members   -  Reputation: 198

Like
1Likes
Like

Posted 27 February 2013 - 03:16 AM

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, 27 February 2013 - 03:50 AM.


Sponsor:

#2 Mito   Members   -  Reputation: 855

Like
0Likes
Like

Posted 27 February 2013 - 04:44 AM

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.



#3 Earthmark   Members   -  Reputation: 198

Like
0Likes
Like

Posted 27 February 2013 - 10:18 AM

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



#4 Mito   Members   -  Reputation: 855

Like
0Likes
Like

Posted 27 February 2013 - 10:49 AM

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



#5 Earthmark   Members   -  Reputation: 198

Like
0Likes
Like

Posted 27 February 2013 - 12:29 PM

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.



#6 Mito   Members   -  Reputation: 855

Like
0Likes
Like

Posted 27 February 2013 - 01:07 PM

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



#7 Earthmark   Members   -  Reputation: 198

Like
0Likes
Like

Posted 27 February 2013 - 01:14 PM

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, 27 February 2013 - 01:16 PM.


#8 Mito   Members   -  Reputation: 855

Like
0Likes
Like

Posted 27 February 2013 - 01:35 PM

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?



#9 Earthmark   Members   -  Reputation: 198

Like
0Likes
Like

Posted 27 February 2013 - 02:21 PM

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.


Edited by Earthmark, 27 February 2013 - 02:28 PM.


#10 Earthmark   Members   -  Reputation: 198

Like
0Likes
Like

Posted 27 February 2013 - 09:03 PM

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);
	}
}


#11 Mito   Members   -  Reputation: 855

Like
0Likes
Like

Posted 28 February 2013 - 10:36 AM

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



#12 Earthmark   Members   -  Reputation: 198

Like
0Likes
Like

Posted 28 February 2013 - 02:45 PM

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

 

Also to load into your current domain you do AppDomain.CurrentDomain.Load, not Assembly.LoadFile. LoadFile makes an assembly as an object so you can add it with AppDomain.CurrentDomain.Load, hence why AppDomain.CurrentDomain does not have a LoadFile method.

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();
foreach (var assem in dllNames.Select(Assembly.LoadFile))
{
	try
	{
		assem.GetTypes();
		catalog.Catalogs.Add(new AssemblyCatalog(assem));
	}
	catch (ReflectionTypeLoadException e)
	{
	}
}

 

 

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.



#13 Mito   Members   -  Reputation: 855

Like
0Likes
Like

Posted 01 March 2013 - 05:14 AM

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

#14 Earthmark   Members   -  Reputation: 198

Like
0Likes
Like

Posted 01 March 2013 - 10:21 AM

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 blink.png, 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.biggrin.png



#15 Mito   Members   -  Reputation: 855

Like
0Likes
Like

Posted 01 March 2013 - 11:46 AM

i'll probably have the same issues biggrin.png

 

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



#16 Earthmark   Members   -  Reputation: 198

Like
0Likes
Like

Posted 01 March 2013 - 12:02 PM

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, 01 March 2013 - 12:02 PM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS