2

SEE EDITS AT THE END.

I have an app that requires to user to install a 3rd party application for mine to run. I'd like to make my application provide a warning to the user if they have forgotten to install this 3rd party app instead of just quitting as a result of trying to access a missing assembly.

In C#, I'd like to check if an assembly is included.

I thought I could use:

object.ReferenceEquals(Oject, null)

But but object.ReferenceEquals does not like to take Type as an input.

I tried:

    var type = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
        from type2 in assembly.GetTypes()
        where type2.Name == "Oject"
        select type2);
    if (type == null) {...}

But Visual Studio shows me that type can never be null.

So: Is there a simple way I can detect if I forgot to include an assembly before I access it (and the app just quits with no warning or message telling the user WHY it quit)?

I thought I could use

try
{
    types = assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
    types = ex.Types.Where(p => p != null).ToArray();
}

from: Missing types using reflection on DLL but I'm doing this check from Program.cs that is a static class.

EDIT: It turns out that I have the referenced assemblies but that these assemblies may not have the correct logic installed. So the references came along with all the binaries but since the 3rd party app was not installed, those binaries went bonkers when they could not reach their intended targets and it is those binaries that seem to be failings.

So... I still have this issue but it may explain I cannot "Catch" ??

Ed Landau
  • 966
  • 2
  • 11
  • 24
  • 1
    Anything useful in https://stackoverflow.com/questions/5198367/how-to-try-and-catch-assembly-not-found or https://stackoverflow.com/questions/15147811/how-can-i-check-that-a-referenced-assembly-is-available-at-runtime? Seems like the AssemblyResolve event may be a good keyword for further searches? – CompuChip Jul 14 '17 at 22:16
  • 1
    Side note: if you would not put all your code into Main you'd not even have this problem... try/catch around a method that calls third party assembly would be enough. – Alexei Levenkov Jul 14 '17 at 22:21
  • in your second code snippet you need `if(!type.Any())`. your linq returns a list of types, not one type. The list will never be null but it can be empty – pm100 Jul 14 '17 at 22:22
  • Thank you Alexei. I tried this but it does not "Catch". Process just ends. – Ed Landau Jul 14 '17 at 23:20

1 Answers1

1

An interesting fact about type loading in .NET. A type is loaded upon entering a method that uses it. An assembly is loaded when the first type is loaded. So, example code below (assuming "SomeType" is a type in the assembly you are looking for)

So by this logic you can have:

static void Main() {
    if (CanLoad()) {
        DoStuff();
    } else {
        Console.WriteLine("Some error message");
    }
}

static void DoStuff() {
    // Ok to reference SomeType here
}

private static bool CanLoad() {
    try {
        TryLoad();
        return true;
    } catch {
        return false;
    }
}

private static void TryLoad() {
    Type t = typeof(SomeType);
}

With this code, what happens is this. Main calls CanLoad normally. CanLoad doesn't need any fancy type, so it happily starts up, and then attempts to call TryLoad. TryLoad, however, has a reference to "SomeType", so when the compiler attempts to enter that method, before executing any part of it, it attempts to load the assembly containing "SomeType". If this fails, the method throws a FileNotFoundException trying lo load it. We catch that in CanLoad and return false.

It's very important that neither "Main" nor "CanLoad" have any references to that assembly at all (even after the check), or they will crash before the check (remember, the loads are done when entering a method, not on reaching the line), but "DoStuff" can reference whatever it wants.

  • My app just terminates without getting to Catch. I've tried using: "Using (Object o = Object.xx) and the app just terminates without getting to the Catch part. – Ed Landau Jul 14 '17 at 23:21
  • Do you have two different methods "CanLoad" and "TryLoad"? Or did you try to combine them into one? –  Jul 15 '17 at 00:27
  • Interesting. Ok. 1) I'm not sure I get why separating them is different and 2) this code runs fine. TryLoad works fine. I made an EDIT to my original question. It turns out the assembly is referenced and can load but 3rd party software that this assembly references is missing so the "SomeObject" loads but when trying to initialize, somehow fails and I cannot "Catch" the failure. It just exits. Likely the code does not raise an exception? – Ed Landau Jul 16 '17 at 14:16
  • If you can't catch it, they could be doing any number of things, like calling Environment.Exit, or some other non-exception based exit. Without more details, I can't be much help. I tried to explain why separating the methods mattered with regards to the timing of the type loading. –  Jul 19 '17 at 05:14