MessageBox.Show время от времени не отображается при отлове исключения - PullRequest
0 голосов
/ 14 октября 2019

Я пишу расширение Visual Studio на C # и получаю странное поведение при управлении исключениями и отображении сообщений об ошибках. По сути, я просто хочу добавить некоторые детали к сообщению об исключении, чтобы помочь мне разобраться в случае возникновения проблемы.

Все начинается с команды в элементе контекстного меню, и я подозреваю, что это может быть связано с управлением потоками за механизмом асинхронного ожидания / ожидания. Но я не уверен, что правильно угадал, и я не могу найти никакого решения. ПОМОГИТЕ!

Это начинается с моего обратного вызова пункта меню:

internal sealed class My_RunAnalysis
{
    //...
    public static async Task InitializeAsync(AsyncPackage package)
    {
        // Switch to the main thread - the call to AddCommand in PS_RunAnalysis's constructor requires
        // the UI thread.
        await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);

        OleMenuCommandService commandService = await package.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService;
        Instance = new My_RunAnalysis(package, commandService);
    }

    //...
    private async void ExecuteAsync(object sender, EventArgs e)
    {
        try
        {
            await My_ViewModel.RunAnalysisAsync();
        }
        catch (Exception exc)
        {
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);

            MessageBox.Show(exc.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
    }
}

//...

class My_ViewModel
{
    async public static Task RunAnalysisAsync()
    {
        await My_Model.GetResultsListAsync();
    }
}

//...

class My_Model
    async public static Task GetResultsListAsync()
    {
        ResultsList = new My_ResultsList();

        var rawResultsList = await QueryServerAsync<RawResultsListResponse>("GET", My_Request.GetResults());

        //...
    }

    async public static Task<JsonResponse> QueryServerAsync<JsonResponse>(string method, 
        string request)
    {
        try
        {
            HttpResponseMessage response;

            switch (method)
            {
                case "GET":
                    response = await _httpClient.GetAsync(request);
                    break;
                case "POST":
                default:
                    StringContent httpContent = new StringContent("", Encoding.UTF8, "application/json");
                    response = await _httpClient.PostAsync(request, httpContent);
                    break;
            }

            if (!response.IsSuccessStatusCode) //<<<<<<CASE #1
            {
                throw new My_Exception(
                response.ReasonPhrase,
                "Exception while querying server for " + request);
            }

            string serializedJson = await response.Content.ReadAsStringAsync();
            // CASE #2>>>>>
            var jsonResponse = serializer.Deserialize<JsonResponse>(serializedJson); 

            return jsonResponse;
        }
        catch (Exception e)
        {
            throw new My_Exception(
                e.Message,
                "Exception while querying server for " + request);
        }
    }

Странно то, что:

  • Когда возникает ошибка в случае #1, и я создаю пользовательское исключение (мой сервер ответил, но произошла внутренняя ошибка, и у меня есть чистый код ошибки), MessageBox в перехвате My_ViewModel :: RunAnalysisAsync () будет отображаться правильно и немедленно.

  • Когда в случае № 2 возникает собственное исключение (мой сервер ответил неправильно сформированным json, и я получаю исключение от serializer.Deserialize), MessageBox в перехвате My_ViewModel :: RunAnalysisAsync () не будет отображаться,IDE будет зависать примерно 15 секунд перед перезапуском (и все равно не будет отображать MessageBox).

Есть идеи, что случилось?

Спасибо!

РЕДАКТИРОВАТЬ:

Видя, что шаблон для моей пользовательской команды также инициализируется с помощью SwitchToMainThreadAsync, я попытался сделать то же самое с методом Execute. Я обновил приведенный выше код, но он по-прежнему не работает: исключение, выданное serializer.Deserialize, будет по-прежнему останавливать пользовательский интерфейс на 10–15 секунд, а MessageBox не будет отображаться!

Также обратите внимание, что отладчик может немедленно перейти к "await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync (package.DisposalToken);"и перейдите к следующему шагу в MessageBox. Я бы предпочел предположить, что это означает, что переключение на основной поток происходит немедленно, но все еще что-то не так ...

Есть идеи, что случилось? Мне действительно нужно надежно фиксировать исключения ...

Ответы [ 2 ]

1 голос
/ 18 октября 2019

Я не смог найти никакого объяснения MessageBox, работающему над делом, а не над другим. Я закончил тем, что пошел к некоторому решению журнала, используя FileStream.WriteAsync. Следовательно, все остается асинхронным, и мне больше не нужно использовать MessageBox.

0 голосов
/ 14 октября 2019

используйте await JoinableTaskFactory.SwitchToMainThreadAsync(); для переключения на основной поток JoinableTaskFactory является членом AsyncPackage. Если это все еще не работает, попробуйте

public static void ShowMessageBox(string title, string text)
        {
            Microsoft.VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread();

            IVsUIShell uiShell = Microsoft.VisualStudio.Shell.ServiceProvider.GlobalProvider.GetService(typeof(SVsUIShell)) as IVsUIShell;
            Guid clsid = Guid.Empty;
            int result;
            Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox(
                       0,
                       ref clsid,
                       title,
                       text,
                       string.Empty,
                       0,
                       OLEMSGBUTTON.OLEMSGBUTTON_OK,
                       OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
                       OLEMSGICON.OLEMSGICON_INFO,
                       0,        // false
                       out result));
        }
...