C# MessageBox.偶尔显示don';捕获异常时不显示
我正在用C#编写一个visualstudio扩展,在管理异常和显示错误消息方面出现了一种奇怪的行为。基本上,我只想在异常消息中添加一些细节,以帮助我在出现问题时进行调查 这一切都是从上下文菜单项上的一个命令开始的,我怀疑这可能与异步/等待机制背后的线程管理有关。但我不确定我的猜测是否正确,也无法找到任何解决方案。救命啊 它从我的菜单项回调开始:C# MessageBox.偶尔显示don';捕获异常时不显示,c#,visual-studio-extensions,C#,Visual Studio Extensions,我正在用C#编写一个visualstudio扩展,在管理异常和显示错误消息方面出现了一种奇怪的行为。基本上,我只想在异常消息中添加一些细节,以帮助我在出现问题时进行调查 这一切都是从上下文菜单项上的一个命令开始的,我怀疑这可能与异步/等待机制背后的线程管理有关。但我不确定我的猜测是否正确,也无法找到任何解决方案。救命啊 它从我的菜单项回调开始: internal sealed class My_RunAnalysis { //... public static async Tas
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);
}
}
内部密封类My\u运行分析
{
//...
公共静态异步任务InitializeAsync(异步包)
{
//切换到主线程-在PS_RunAnalysis的构造函数中调用AddCommand需要
//用户界面线程。
等待ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
OleMenuCommandService commandService=await package.GetServiceAsync((typeof(IMenuCommandService)))作为OleMenuCommandService;
实例=新的My_RunAnalysis(包、commandService);
}
//...
私有异步void ExecuteAsync(对象发送方,事件参数e)
{
尝试
{
等待My_ViewModel.RunAnalysisAsync();
}
捕获(异常exc)
{
等待ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);
MessageBox.Show(exc.Message,“Error”,MessageBoxButtons.OK,MessageBoxIcon.Warning);
}
}
}
//...
将My_ViewModel分类
{
异步公共静态任务RunAnalysisAsync()
{
等待My_Model.GetResultsListAsync();
}
}
//...
我的课堂教学模式
异步公共静态任务GetResultsListAsync()
{
ResultsList=新建My_ResultsList();
var rawResultsList=await queryserver async(“GET”,My_Request.GetResults());
//...
}
异步公共静态任务QueryServerAsync(字符串方法,
字符串请求)
{
尝试
{
HttpResponseMessage响应;
开关(方法)
{
案例“GET”:
response=wait\u httpClient.GetAsync(请求);
打破
案例“职位”:
违约:
StringContent httpContent=newStringContent(“,Encoding.UTF8,“application/json”);
response=wait_httpClient.PostAsync(请求,httpContent);
打破
}
如果(!response.issucessStatusCode)/使用等待JoinableTaskFactory.SwitchToMainThreadAsync();
切换到主线程JoinableTaskFactory
是异步包的成员。
如果仍然不起作用,试试看
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));
}
我找不到任何关于MessageBox处理一个案例而不是另一个案例的解释。我最终使用FileStream.WriteAsync找到了一些日志解决方案。因此,所有内容都保持异步,我不必再使用MessageBox了。您是否正在逐步完成创建我的\u异常
的捕获过程,以及创建My_Exception
?MessageBox与任何对话框一样,需要一个所有者窗口。该窗口保证位于其顶部,因此始终可见。如果不强制您指定所有者,则会有点太有用,它会在当前线程上拾取活动窗口。在该代码中,它会在当前线程上落下。调用是在线程池线程不拥有任何窗口。这使得桌面窗口成为所有者。它现在出现在VS主窗口后面的几率总是很高。嗨,Ed!谢谢你的回复。是的,我确认在这两种情况下我都可以单步执行捕获,在这两种情况下我也可以单步执行My_Exception构造函数。我不明白它为什么会工作!response.IsSuccessStatusCode而非序列化程序。反序列化异常。代码的相同部分与相同的上下文相同。有什么想法吗?嗨,Hans!谢谢你的回复。我了解你关于设置对话框所有者的详细信息。但它如何在!response.IsSuccessStatusCode而不是序列化程序上工作。反序列化异常?嗨!谢谢你的回复。我这两个都已初始化,没有更改:仍然失败,serializer.Deserialize上出现异常。UI将挂起10到15秒,MessageBox最终不会显示。还有其他想法吗?顺便说一句,使用ThrowifNotNuithRead()时,编译器失败,并显示以下消息:错误VSTHRD109:在异步或任务返回方法中,避免在不在主线程上时引发。请改为切换到所需的线程。我必须删除此行…已替换为Wait ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken)。是否与我的问题“在异步或任务返回方法中避免在不在主线程上时引发”有关?那么在异步或任务返回方法中处理异常的最佳实践是什么?因为我需要的方法确实会引发异常(serializer.Deserialize)…关于我发现的:,。我可以确认我确实在catch块中获取了异常,但问题仍然是,当从serializer.Deserialize获取异常时,我无法可靠地获取MessageBox显示。为什么它在case#1而不是case#2下工作?为什么我在case#1而不是case#2上的线程正确?