0

I have noticed that in some situations, where I do not distribute a particular dll, which is required by application, the application doesn't not provide any errors, it just does not load (show on screen). It behaves like you haven't started it.

Does anyone know why is this happening?

Edit: Steps to reproduce:

  1. Create a solution with WPF app project and class library project (ReferenceDll).
  2. Add reference in WPF app project to class library project.
  3. In class library, add this method to Class1

    public int Calculate(int a, int b) { return a + b; }

  4. place this code in App.OnStartup:

    try
    {
        int result = new ReferenceDll.Class1().Calculate(2, 4);
    }
    catch (Exception ex)
    {
        File.WriteAllText(@"D:\Test\error.txt", ex.ToString());
    }
    
  5. build the solution then remove the ReferenceDll from the bin folder. Run the app.

No file will be created, app will not show. Even if you move Try catch code in the main view, in some button click event, Catch{} will never be fired and it will display non-informative message

AppName has stopped working.

and offer options to debug, which is of no use to end-user.

pangabiMC
  • 784
  • 5
  • 20
Goran
  • 6,328
  • 6
  • 41
  • 86

2 Answers2

2

If you don't have any Trace.WriteLine statements, then I suggest you add some. Add some to the exception handlers. Also you could use the following free tool to capture trace and try and narrow it down that way.

http://technet.microsoft.com/en-us/sysinternals/bb896647.aspx

You could also override the Onstartup method in app.xaml.cs and instantiate your application from there and catch any exceptions and output to trace.

Update

I have tried the steps that you have indicated in your update and the application loaded without any problems. The next thing that I would suggest would be to check what version of the .net framework that you have on your environment that you have deployed to. Look at this link, if you need help to do that:

http://msdn.microsoft.com/en-us/kb/kbarticle.aspx?id=318785

Update

Put your error logging in a handler like the one in the answer to this question and you will see the error. Just tried this with your example and it worked. The error tells you exactly what is wrong:

System.IO.FileNotFoundException: Could not load file or assembly 'ReferenceDll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified. File name: 'ReferenceDll, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' at WPFApp.App.OnStartup(StartupEventArgs e) at System.Windows.Application.<.ctor>b__1(Object unused) at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs) at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)

WRN: Assembly binding logging is turned OFF. To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1. Note: There is some performance penalty associated with assembly bind failure logging. To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog

WPF window crashes on startup, or it starts but hangs and does not render contents

Community
  • 1
  • 1
Justin Bannister
  • 618
  • 5
  • 11
1

That may happen when the exception is thrown on a secondary thread. See remarks section on this page:

Standalone or browser-hosted WPF applications use the Application class to detect unhandled exceptions (see DispatcherUnhandledException). However, Application can only detect unhandled exceptions that are thrown on the same thread that the Application class is running. Usually, an application will have one main user interface (UI) thread, so the unhandled exception detection behavior of the Application class is adequate. However, unhandled exceptions that are thrown on secondary threads are not automatically detected by the Application class on the main UI thread.

You can try using this event to catch detect the exception and log the error: AppDomain.UnhandledException Event

AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(MyHandler);

static void MyHandler(object sender, UnhandledExceptionEventArgs args) {
   Exception e = (Exception) args.ExceptionObject;
   Console.WriteLine("MyHandler caught : " + e.Message);
}

UPDATE:

Apart from the threading issue it also can the cause if you put your try...catch block to the wrong place. Consider this example:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        Do();

    }

    private void Do()
    {
        try
        {
            int result = new ClassLibrary1.Class1().Calculate(2, 4);
        }
        catch (System.Exception ex)
        {
            Console.WriteLine("MyHandler caught by try...catch: " + ex.Message);
        }
    }
}

This will result in an exception at the line where the Do() is called since the CLR here tries to resolve the assembly at this point. The exception is not caught and the app terminates.

But if you try this one:

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        try
        {
            Do();
        }
        catch (System.Exception ex)
        {
            Console.WriteLine("MyHandler caught by try...catch: " + ex.Message);
        }
    }

    private void Do()
    {
        int result = new ClassLibrary1.Class1().Calculate(2, 4);
    }
}

The output is:

MyHandler caught by try...catch: Could not load file or assembly 'ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

Note that the UnhandledException event is not fired when you subscribe to it in the same function where the assembly is referenced. This works as well:

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        AppDomain currentDomain = AppDomain.CurrentDomain;
        currentDomain.UnhandledException += new UnhandledExceptionEventHandler(
            (sender, args) =>
            {
                Exception ex = (Exception)args.ExceptionObject;
                Console.WriteLine("MyHandler caught by UnhandledException handler: " + ex.Message);
            });

        Do();
    }

    private void Do()
    {
        int result = new ClassLibrary1.Class1().Calculate(2, 4);
    }

Result:

MyHandler caught by UnhandledException handler: Could not load file or assembly 'ClassLibrary1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.

Hope it helps.

pangabiMC
  • 784
  • 5
  • 20
  • Its not a problem with secondary thead, I have updated question and given steps to reproduce. – Goran Nov 28 '12 at 17:41
  • The assemblies in .net are loaded on demand, when the function that uses the assembly is called. In your case it's the OnStartup, that's why the exception is not caught. Try to put the call to the Calculate function to a method CallCalculate, in class App and call that method from App.OnStartup. If you put CallCalulate in a try catch block the missing dll exception will be caught. – pangabiMC Nov 29 '12 at 12:43
  • My solution above will also work if you put this code in the App.Startup and the call to the Calculate in another function. It's a generic way of letting the user know about unhandled exceptions before letting the app die. – pangabiMC Nov 29 '12 at 12:45
  • In my case it doesnt, as I said, I copied the try..catch block in the button click event ont he MainView, and it immediatelly displaus the message: AppName has stopped working, and offers to debug it. Also, your solution will not work also. Have you tried what you are suggesting at all? Having an UnhandledExcewptionEventHandler is a must in all application, so I always use it. – Goran Nov 29 '12 at 14:13
  • I see your point, but I cannot say I like it. So, does this mean that the only way to avoid this, is to wrap a call to external dll into separate method? What about 3rd party dlls thzt are used to build UI. I have no control over these dlls, so I am unable to do Try...catch... What should I do then? – Goran Nov 29 '12 at 17:30
  • Check this answer on a similar thread, it might help: http://stackoverflow.com/a/1111281/928651 Personally I can hardly imagine a case where I wouldn't want to let the app crash because of a missing dll, the only thing I'd want to add was a meaningful error message, which you can provide by using the UnhandledException event. You still need to extract your external calls to a method though. – pangabiMC Nov 30 '12 at 09:22
  • This is exactly what I want - to display to user a meaningful message. I am again unable to catch anything in the UnhandledException event. Maybe I am overseeing something. So, in your case, when you put a 3rd party control in WPF UI (a CustomTextBox), and then build the project, remove the CustomTextBox.dll from the build folder, it will catch exception in Unhandled exception? For me, it doesn't, it just doesn't do anything - no application window, no error message saved in the file. However, if I make any other exception manually in code (divide by zero, for example), exception is saved. – Goran Nov 30 '12 at 11:12