0

I ran a windows service i developed on a server that had a pre-required software component missing.

Sure enough the service crashed with a System.IO.FileNotFoundExcpetion: could not load file or assembly...

The thing is, when i deploy the exact same service, complied in debug, the catch block around my failing code is actually hit, and i get the chance to react (log, retry).

in example:

private void SampleMethodInService()
{
    try
    {
        // this method uses objects that reside in an assembly that`s missing
        MethodInMissingAssembly();
    }
    catch(Exception e)
    {
         // i'd like to log what happened, but don't get the chance.
    }
}

if the code above is compiled in debug, the catch block handles the exception. if the code above is compiled in release, catch block is not hit and the process fails.

My question is: why is this ?

I have googled around for quite a while, but could not find any clues.

Menahem
  • 3,974
  • 1
  • 28
  • 43
  • Scattered `catch` blocks are not the correct way to log exceptions. If you had added a global handler for unhandled exceptions and put your logging code there, you would have seen the trace. – Cody Gray - on strike Feb 15 '16 at 14:57
  • @CodyGray the problem with that way of doing it is that i don't get to continue what the service was doing. so in general im not sure what you say as a rule is correct. – Menahem Feb 15 '16 at 15:02
  • Maybe you could try using Sysinternal's procmon on your exe (https://technet.microsoft.com/en-us/sysinternals/processmonitor.aspx). You should see when the process is trying to find your assembly. If you mix that with some logging you could check if things happen in the same order in debug and in release – Evren Kuzucuoglu Feb 15 '16 at 15:05
  • @EvrenKuzucuoglu since the code is in a try block , the optimizer will not remove the code out of it. that would change the semantics drastically and all bets are off for all of us. – Menahem Feb 15 '16 at 15:10
  • I don't think it would be optimised away, but maybe in release the application actually tries to load the assembly way before you call that method. I'm merely suggesting procmon as a way to just verify when the debug and release version of your binaries are trying to open that dependency. With it you could see the timeline and results of calls from the CLR trying to get hold of the assembly. – Evren Kuzucuoglu Feb 15 '16 at 15:13
  • @EvrenKuzucuoglu i see.cool idea, ill try and report back ! – Menahem Feb 15 '16 at 15:15
  • I also get some search results suggesting using Fusion logging: http://www.hanselman.com/blog/BackToBasicsUsingFusionLogViewerToDebugObscureLoaderErrors.aspx – Evren Kuzucuoglu Feb 15 '16 at 15:20
  • chat is blocked from my office. – Menahem Feb 15 '16 at 15:30
  • well, i did the procmon dance, and i see that the fusion logging takes place earlier in debug (!) than in release. (i am old friends with fusion log and have it turned on on my dev machine) – Menahem Feb 15 '16 at 15:33
  • @Menahem I can't think of any reason nor can I find anything useful on the net. Is the assembly loaded just before that call? Anyway to trace that information throughout your code to check when it gets loaded? You can still try loading the assembly at the very start of your application, store the result somewhere then use that result as a check before calling the method – Evren Kuzucuoglu Feb 15 '16 at 17:38

1 Answers1

0

It depends of a number of factors.

The first obvious possibility is that when you load your code as a service, it is using the missing dependency before, somewhere else than the method where you are catching the exception. The application will crash the first time it tries to load it.

If you are sure that this method is the first one using this dependency, it is still possible that the dependencies are loaded when the application start. Some runtime environments will do that (e.g. asp .net), in which case catching in the method calling the assembly will be pointless. If you run the same thing in debug (or in a unit test) you might get a different behaviour than within IIS (I know you are not using IIS here, but I am just giving an example).

More information here.

A possible solution would be to load all referenced assemblies by reflection at your application's entry point (App_Start, Main(), etc), and catch there. See this SO question for more information.

There might be some other solutions regarding why is it possible that an assembly is missing. I am guessing it is not actually deployed with your application. Are you expecting it to be in the GAC? Is there maybe a way to just check that a 3rd-party dependency is installed using registry? You could raise a more informative error if that is the case.

Community
  • 1
  • 1
Evren Kuzucuoglu
  • 3,781
  • 28
  • 51
  • i ran the service with the exact same code coplied in debug - the exception is handeld, ran the service with the exact same code coplied in release - the exception is not handled. both cases run as a service – Menahem Feb 15 '16 at 14:59
  • because of the previous comment, the first and second points are not relevant. i'm not looking for a way to pre-detect this situation, rather to understand why the compilation mode changes the behavior this way. – Menahem Feb 15 '16 at 15:07
  • ok not the correct answer then. Just to make sure, is there anything in your code that runs differently in debug, like #ifdef debug? I can't think of a release optimisation that would create this situation. – Evren Kuzucuoglu Feb 15 '16 at 15:08
  • Thanks Evren, i don't have any pre compiler conditionals either – Menahem Feb 15 '16 at 15:11