所以我在客户端EXE和服务器EXE之间实现了localhost WCF Named Pipes通信。我可以通过localhost在服务器上调用类方法。所以,它就像一个IPC / RPC。但是,如果服务器的类方法需要很长时间才能执行,那么最好将它放入一个线程中,以便服务器类方法完成并在后台运行该线程。好的,很好,但是当线程完成其长任务时,我想提醒客户端而不必在客户端上使用会检查该类方法的计时器。命中类方法的计时器比引发的事件效率低得多。这就像我需要从服务器上提升客户端上的事件。是否有一种简单的方法可以做到这一点或至少模拟它,而不需要很多令人困惑的工作?
答案 0 :(得分:1)
这是根据我对OP的问题的评论制定的答案
你可以制作你的WCF方法asynchonous然后它就是async/await
的简单问题,或完全取消WCF并使用内置异步NamedPipeClientStream
(仍然等待兼容) 。在废除冗长的XML SOAP编码时,更不用说后者的速度提升
OP:
@MickyD你现在对async / await做了正确的事情我已经研究过并实现了一个有效的测试。这使我几乎能够在长时间运行的任务中使用最少的代码行来模拟回调
e.g。建立OP的答案,但要正确使用async/await
:
private async void button1_Click(object sender, EventArgs e) // <-- note async
{
label1.Text = await client.GetDataAsync(textBox1.Text); // <-- note await. New method
}
现在你可能想要使用Task.Run
,但这样做很糟糕,因为:
Task.Run
最适合我们不支持的计算绑定操作。 Task.Run
最多会使用昂贵的线程池线程我们正在执行I / O操作,因此可以从I / O完成端口和“任务I / O绑定操作中存在的IOCP没有线程” philosphy中受益。因此,当我们通过GetDataAsync
进行服务器调用时,我们不会浪费线程等待结果。
在这里,我们通过等待来模拟冗长的操作,但不是使用Sleep
知道的Task
,而是使用Task.Delay
这是一个等待操作。
Task<string> async GetDataAsync (string text)
{
await Task.Delay (Timespan.FromSeconds(5));
return text + " processed";
}
答案 1 :(得分:0)
因此,我们假设您在UI中点击了一个按钮,该按钮在WCF服务上执行WCF同步方法调用,并且该同步方法需要很长时间才能运行。显然,在执行长时间运行的任务时,您不希望阻止UI更新。当然,您可能正在考虑回调。在中,您调用服务器,服务器上的类方法生成一个线程并运行该任务,一旦完成,它就会通过回调将结果返回给客户端。
实际上,要设置WCF上的所有内容都涉及许多复杂,令人困惑,记录不良的步骤。但是,这是一种更简单的方法,它根本不涉及WCF代码,并且不会让您更改WCF服务上的任何内容,也不会编辑任何WCF配置。这个技巧是在.NET 4.5及更高版本中引入的。它被称为async
和await
。下面是一个按钮单击的示例,它调用WCF服务方法,该方法需要很长时间才能运行,然后在结束时返回结果,但GUI不会锁定并且可以处理其他事件
1。首先,要模拟慢速任务,请编辑WCF服务项目的共享类方法,并在返回结果之前添加此行,以便模拟5秒的暂停:
Thread.Sleep(5000); // requires using System.Threading;
就我而言,我把它放在我的GetData()
方法中。
2。现在切换到您的WCF客户端项目。您可能有一个按钮单击处理程序,如下所示:
private void button1_Click(object sender, EventArgs e)
{
string returnString = client.GetData(textBox1.Text));
label1.Text = returnString;
}
所以,切换它有三个小的改动:
一个。添加using System.Threading.Tasks;
。
湾在按钮点击处理程序上将private void...
更改为private async void...
。
℃。使用慢速方法调用await Task.Run(...)
。
因此,代码看起来像这样:
private async void button1_Click(object sender, EventArgs e)
{
// Task.Run() requires "using System.Threading.Tasks;"
string returnString = await Task.Run(() => client.GetData(textBox1.Text));
label1.Text = returnString;
}
最终结果是当您单击WCF客户端项目中的按钮时,在后台线程中的WCF服务项目上调用GetData()类方法,并在完成后返回到{{1 }语句并将结果返回给变量赋值。在我的情况下,我点击了按钮,没有任何事情发生5秒 - 带有结果字符串的标签没有改变。但是,GUI没有被锁定 - 我可以拖动窗口,键入其他字段,单击其他表单按钮,等等。所以,它几乎就像一个回调事件处理程序,但并不完全如此。尽管如此,它仍然提供相同的功能,并且在大多数情况下可用于代替回调事件处理程序。它涉及的代码少得多。