我已经创建了一个WCF服务应用程序,并且基本上没有更改除名称之外的任何内容,默认合同就在那里并且包含一个返回String的方法GetData(Int32)
。
然后我创建了 WPF客户端应用程序,目标是 .NET FW 4.5 ,所以在那里我添加了对所述服务的服务引用,我可以选择包含基于任务的异步变体生成的服务客户端中的合同方法
现在,当我尝试使用该服务时,就像这样:
using (var client = new RhaeoServiceClient())
{
client.GetDataAsync(17).ContinueWith(t => MessageBox.Show(t.Result));
MessageBox.Show("inb4");
}
当从Button单击处理程序执行时,窗口停止,按钮保持按下一秒左右,然后"inb4"
消息显示,所以在我看来,任务在主线程上运行并等待网络,因此冻结用户界面。
"inb4"
点击后没有立即显示,似乎在任务执行后等待,就像我说的,一两秒钟。在"inb4"
显示之后,下一个带有结果的消息框也会显示,但是对我来说有趣的是接下来的消息框不等我关闭第一个消息框,它只是在第一个消息框后几乎立即弹出第一个是节目。
这令人困惑,因为它使得看起来延续代码实际上是在不同的线程中运行而不关心主线程是否被第一个消息框阻止。但它如何显示消息框,只能从UI线程显示(对吗?)?
为什么第一个消息框在任务执行后等待,然后显示,然后被下一个消息框覆盖而不被关闭?
答案 0 :(得分:0)
t.Result将阻塞调用线程,直到任务完成。您可以通过将async / await关键字与WCF调用结合使用来实现所需的结果。
private void button1_Click(object sender, EventArgs e)
{
CallGetDataAsync(17);
MessageBox.Show("inb4");
}
private async void CallGetDataAsync(int number)
{
string result = null;
var client = new Service1Client();
try
{
// After this line, control is returned to the calling method; the ConfigureAwait(true)
// explicitly indicates that when execution resumes, it should attempt to marshall back
// to the calling thread. If you change it to false, you can see that the subsequent
// messagebox does not stop you from interacting with your main form.
result = await client.GetDataAsync(number).ConfigureAwait(true);
// when the async service call completes, execution will resume here
client.Close();
}
catch
{
try
{
client.Close();
}
catch
{
client.Abort();
}
throw;
}
// display the MessageBox, this should block the UI thread
MessageBox.Show(result);
}
针对与客户端在同一台计算机上运行的服务运行此操作,很难看到发生了什么,因为WCF服务调用将返回足够快的速度,以便在服务结果消息之后仍然显示“inb4”。延迟样本服务方法有助于更好地说明行为。
public string GetData(int value)
{
return Task.Delay(TimeSpan.FromSeconds(5)).ContinueWith(_ => string.Format("You entered: {0}", value)).Result;
}
对于您的上一个问题,后台线程可以调用MessageBox。但是,如果这样做,它将不会作为模态并阻止您的主要表单。