Как я могу получить полезную информацию об ошибках WPF.NET с пользовательской машины?

У меня есть приложение WPF, которое разбивается, как только я получаю его на машинах, на которых не установлена ​​среда разработки. Если это обман, я могу закрыться, но я не нашел поискового fu эквивалентный вопрос. Похоже, что я получаю исключение XamlParseException, но ничего более полезного. Мне нужно получить полезную информацию.

Прохождение журналов событий Windows 7 дает мне этот журнал ошибок:

Fault bucket , type 0
Event Name: CLR20r3
Response: Not available
Cab Id: 0

Problem signature:
P1: MyApp.exe
P2: 1.0.0.0
P3: 4b88323d
P4: PresentationFramework
P5: 3.0.0.0
P6: 4a174fbc
P7: 624f
P8: e1
P9: System.Windows.Markup.XamlParse
P10: 

Attached files:
C:\Users\Mark\AppData\Local\Temp\WER7DC.tmp.WERInternalMetadata.xml

These files may be available here:
C:\Users\Mark\AppData\Local\Microsoft\Windows\WER\ReportArchive
 \AppCrash_generatortestbed_4fa7dff09a9e893eb675f488392571ced4ac8_04ef1100

Analysis symbol: 
Rechecking for solution: 0
Report Id: cd55060c-271f-11df-b6ff-001e52eefb8e
Report Status: 1

Я проверил эти каталоги, а первый не существует, а второй содержит wer файл, который просто перечисляет загруженные DLL.

Я мог бы установить среду разработки на своем тестовом компьютере, но тогда она не будет тестовой машиной, и я вернусь к ней. Я не получаю эту ошибку с установленной средой dev, поэтому я не понимаю, как получить подробное и полезное сообщение об ошибке.

EDIT: создание комментария @Alastair Pitts ниже, здесь, как я заполнил обработку исключений:

    private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) {
        Exception theException = e.Exception;
        string theErrorPath = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\GeneratorTestbedError.txt";
        using (System.IO.TextWriter theTextWriter = new System.IO.StreamWriter(theErrorPath, true)){
            DateTime theNow = DateTime.Now;
            theTextWriter.WriteLine("The error time: " + theNow.ToShortDateString() + " " + theNow.ToShortTimeString());
            while (theException != null) {
                theTextWriter.WriteLine("Exception: " + theException.ToString());
                theException = theException.InnerException;
            }
        }
        MessageBox.Show("The program crashed.  A stack trace can be found at:\n" + theErrorPath);
        e.Handled = true;
        Application.Current.Shutdown();
    }

Надеюсь, я получу то, что мне нужно. Спасибо за помощь!

Ответы

Ответ 1

Процедура, которую я хотел бы использовать, - обработать событие UnhandledException в домене приложения.

Как только вы это сделали, у вас есть несколько вариантов. Занесение исключения в файл, сериализация его для последующей проверки, показывая диалоговое окно с сообщением об исключении.

EDIT: XamlParseException возникает при создании основного окна. Это означает, что вызывается конструктор этого окна. Если вы выполняете какую-либо логику в этом конструкторе, любые результирующие исключения будут бросать XamlParseException. Насколько я понимаю, обработчик UnhandledException все равно поймает это исключение.

Чтобы подключить событие UnhandledException в WPF, добавьте подключение к событию в свой app.xaml

<Application 
   x:Class="DispatcherUnhandledExceptionSample.App"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   StartupUri="MainWindow.xaml"     
   DispatcherUnhandledException="App_DispatcherUnhandledException" />

который затем добавляет метод в ваш app.cs

public partial class App : Application
{
    void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        // Process unhandled exception do stuff below

        // Prevent default unhandled exception processing
        e.Handled = true;
    }
}

MSDN

Ответ 2

Помимо наличия обработчика событий необработанного исключения, который регистрирует трассировку стека, полезно также посмотреть, как аварийные дампы генерируются на машине воспроизведения. Вы упомянули о нем Windows 7, поэтому вы можете искать соответствующие аварийные дампы следующими способами:

  • Панель управления → Все элементы панели управления → Центр действий → "Просмотр проблем с сообщением" в разделе "Обслуживание/Отслеживание решений для неподтвержденных проблем". Это вызывает список приложений, которые разбились, и вы можете развернуть их, чтобы найти файлы дампа и информацию. Найдите ссылку "Просмотреть временную копию этих файлов" в левой нижней части технической проблемы. Это извлечет файлы дампа и покажет их вам в окне проводника.

  • cd/d% ProgramData%\Microsoft\Windows\WER.

Кажется, что WER держит это аварийные дампы под этим каталогом, поэтому то, что я делаю, это dir/s/b для части имени приложения, которое, как я знаю, будет там. Например, я сделал специально предназначенное для использования приложение crashyapp.exe:   

C:\ProgramData\Microsoft\Windows\WER>dir /s/b *crashy*
C:\ProgramData\Microsoft\Windows\WER\ReportQueue\AppCrash_crashyapp.exe_56f8d710d72e31d822d6b895c5c43a18d34acfa1_cab_2823e614
    
Этот каталог содержит файлы hdmp и mdmp для сбоя. Время получения отладчика!

Ответ 3

Ведение журнала исключений (как в ответе от Alastair Pitts) было бы полезным при обнулении источника ошибки.

Наличие XamlParse в строке P9 предполагает, что может возникнуть проблема с инициализацией элемента управления или окна из описания XAML. Может быть сборка, на которую ссылается XAML, которая не найдена на целевом компьютере или не соответствует сигнатуре в XAML.

Edit:

Разбор XAML происходит в InitializeComponent(), который вызывается в конструкторе окна или элемента управления

Ответ 4

В дополнение к ответу Alistair, это внутреннее исключение, которое дало мне подсказки, которые я искал:

public partial class App : Application {
    void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) {
        Exception ex = e.Exception;
        Exception ex_inner = ex.InnerException;
        string msg = ex.Message + "\n\n" + ex.StackTrace + "\n\n" +
            "Inner Exception:\n" + ex_inner.Message + "\n\n" + ex_inner.StackTrace + "\n\n" + 
            Utils.RegistryVersion();
        MessageBox.Show(msg, "Drop Print Batch Application Halted!", MessageBoxButton.OK);
        Utils.MailReport(msg);
        e.Handled = true;
        Application.Current.Shutdown();
    }
}