How to check if a certain assembly exists?
Asked Answered
E

4

8

I'm using the Activator to instantiate a new class based on the short name of an assembly (e.a. 'CustomModule'). It throws a FileNotFoundException, because the assembly isn't there. Is there a way to check if a certain assembly name is present?

I'm using the following code:

System.Runtime.Remoting.ObjectHandle obj = 
    System.Activator.CreateInstance(assemblyName, className);

The main objective is to rather test for the presence of the assembly than to wait for the exception to occur.

Emphysema answered 7/2, 2011 at 9:13 Comment(5)
You mean loaded into the current app domain? What is assemblyName? A fully qualified assembly name or a physical file path?Shoe
@MrDisaapointment the only thing I know is that I have a "CustomModule" in my database. If a CustomModule.dll is present in my bin or GAC (!?) than it will produce the class specified by classname.Emphysema
See my latest update, hopefully this is enough to go on.Shoe
Hm... the .Net 1.1 method uses Assembly.LoadWithPartialName that will return 'null' if the assembly is not present.Emphysema
(?) Yes, if the assembly is not present then you get null, but you've already done all the checking you can (assuming you adopted the code in my answer), so then is the time to get the FileNotFoundException.Shoe
S
10

If you'll notice my comment to your question it will be evident that I'm not rightly sure exactly how you want or need to go about this, but until we have a more elaborate description I can only offer you this in the hope it fits well to your situation (the key is in 'searching' the assemblies):

var className = "System.Boolean";
var assemblyName = "mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
var assembly = (from a in assemblies
                where a.FullName == assemblyName
                select a).SingleOrDefault();
if (assembly != null)
{
    System.Runtime.Remoting.ObjectHandle obj = 
        System.Activator.CreateInstance(assemblyName, className);             
}

.NET 2.0 Compatible Code

Assembly assembly = null;
var className = "System.Boolean";
var assemblyName = "mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";

foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
{
    if (a.FullName == assemblyName)
    {
        assembly = a;
        break;
    }
}

if (assembly != null)
{
    System.Runtime.Remoting.ObjectHandle obj =
        System.Activator.CreateInstance(assemblyName, className);
}

If you want to determine whether or not the file exists before trying to load it (a good practice) then, given you have its name and know the desired location, simply try to find the file when the assembly is being resolved:

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);

var className = "StackOverflowLib.Class1";
var assemblyName = "StackOverflowLib.dll";
var currentAssemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var obj = Activator.CreateInstance(Path.Combine(currentAssemblyPath, assemblyName), className);

static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    var currentAssemblyPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
    if (File.Exists(Path.Combine(currentAssemblyPath, args.Name)))
    {
        return Assembly.LoadFile(Path.Combine(currentAssemblyPath, args.Name));
    }
    return null;
}
Shoe answered 7/2, 2011 at 9:35 Comment(9)
@MrDisappointment, thanks for the code. I failed to specify that I'm working in .Net 2.0Emphysema
Doesn't this return only assemblies that are already loaded in the AppDomain?Disturb
@Disturb has a valid point. I might have a dll present in the bin directory that has not been loaded.Emphysema
I agree, as I stated in my answer and comment: how exactly you wanted to do this was uncertain so I didn't have a lot to go with.Shoe
Hm... the .Net 1.1 method uses Assembly.LoadWithPartialName that will return 'null' if the assembly is not present.Emphysema
(?) Yes, if the assembly is not present then you get null, but you've already done all the checking you can (assuming you adopted the code in my answer), so then is the time to get the FileNotFoundException.Shoe
It seems to work. Because I don't know the full name (only the partial name), I use: if (a.FullName.Contains(partialName)). I have no clue whether this will hold.Emphysema
I've tried the AssemblyResolve example, but that one is not called on my system. I get the message 'The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)'. I'll use the .Net 2.0 example as it works best for my situation.Emphysema
The AssemblyResolve method ought to work just as designed - not sure what's going on there. One note might be to only pass the dll file name to CreateInstance and build the full path in the AssemblyResolve event handler.Shoe
C
2

I think it is better not to try to avoid the exception. The reason is that if you have code like

if (DoesAssemblyExist(asmName)) {
    object = Activator.CreateInstance(typeName);
}
else {
    MessageBox.Show("Assembly does not exist");
}

there is always a risk in a pre-emptive multitasking OS that the assembly might be added/removed between the check and the actual creation. Yes, I realize this risk is minimal, but I still think the exception variant looks better because it is atomic.

Cleavland answered 7/2, 2011 at 10:6 Comment(0)
D
1

Missing assembly definitely constitutes an exception, try/catch FileNotFoundException and handle the situation as per your logic.

Disturb answered 7/2, 2011 at 9:33 Comment(2)
100% true! But I'd like to test for it, rather than to wait for the exception to occur.Emphysema
On the top of my head I don't think you'll manage this easily as you have to emulate a complete probing algorithm. Its also prone to errors (should say application domain install its own probing process). For a first stop look, should you still want this, check this link: [How the Runtime Locates Assemblies]: msdn.microsoft.com/en-us/library/yx7xezcf.aspxDisturb
C
-1

I hope it will help for someone in the future:

On every external .dll you are using, create its own uniqe key, like so:

string key = "fjrj3288skckfktk4owoxkvkfk4o29dic";

And then, when you load your form, for every single external .dll that you have got, simply check if the key is exists like so:

If(isMyLib.Variables.key == key) // continue

else // .dll does not exists or broken.

Calkins answered 11/3, 2017 at 22:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.