有没有一种简单的方法来模拟 WCF 服务和 WCF 客户端之间的事件?
Is there an easy way to simulate events between WCF service and WCF client?
所以我已经实现了客户端 EXE 和服务器 EXE 之间的本地主机 WCF 命名管道通信。我可以通过本地主机在服务器上调用 class 方法。所以,它就像一个 IPC/RPC。但是,如果服务器的 class 方法需要很长时间才能执行,那么我最好将其放入线程中,以便服务器 class 方法完成并在后台运行该线程。好的,很好,但是当线程完成其长期任务时,我想提醒客户端,而不必在客户端上使用计时器来检查 class 方法。计时器触发 class 方法比触发事件效率低得多。这就像我需要从服务器在客户端上引发一个事件。有没有一种简单的方法可以做到这一点或至少模拟它,而不需要做很多令人困惑的工作?
因此,假设您在 UI 中单击了一个按钮,该按钮在 WCF 服务上执行 WCF 同步方法调用,并且该同步方法需要很长时间才能 运行。显然,您不想在 运行ning 长任务执行期间阻止 UI 更新。自然地,您可能会考虑回调。例如,您调用服务器,服务器上的 class 方法生成一个线程并 运行s 该任务,完成后,它 returns 返回到通过回调客户端结果。
实际上,要在 WCF 上进行所有设置涉及许多复杂、令人困惑且记录不完整的步骤。但是有一种更简单的方法,它根本不涉及 WCF 代码,也不涉及您更改 WCF 服务上的任何内容,也不涉及编辑任何 WCF 配置。该技巧在 .NET 4.5 及更高版本中引入。它被称为 async
和 await
。这是一个单击按钮的示例,它调用 WCF 服务方法,该方法需要很长时间才能 运行 然后 return 完成后结果,但 GUI 没有t 锁定并可以处理其他事件。
1。首先,要模拟一个缓慢的任务,编辑您的 WCF 服务项目的共享 class 方法并在 return 结果之前添加此行,以便您可以模拟 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;
.
b。在您的按钮点击处理程序上将 private void...
更改为 private async void...
。
c。将 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 客户端项目中的按钮时,GetData() class 方法在后台线程中调用 WCF 服务项目,完成后,它会出现回到那个 await
语句和 returns 变量赋值的结果。在我的例子中,我点击了按钮,5 秒内没有任何反应——带有结果字符串的标签没有改变。但是,GUI 没有被锁定——我可以拖动 window,在其他字段中键入,单击其他表单按钮,等等。所以,它几乎就像一个回调事件处理程序,但不完全是。尽管如此,它仍然提供相同的功能,并且在大多数情况下可以用来代替回调事件处理程序。而且它涉及的代码少得多。
这是根据我对 OP 问题的评论得出的答案
你可以让你的 WCF 方法 asynchonous 然后这是一个简单的问题 async/await
或者完全取消 WCF 并使用内置异步 NamedPipeClientStream
(这仍然是等待兼容的)。更不用说在取消冗长的XML SOAP 编码
时后者的速度提升
OP:
@MickyD You were right on the async/await thing now that I have studied that and implemented a test that works. That allows me to almost simulate a callback on a long running task and with minimal lines of code
例如以 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 完成端口和 "there is no thread" 中存在的 IOCP 哲学任务 I/O 绑定操作。因此,当我们通过 GetDataAsync
进行服务器调用时,我们不会浪费线程等待结果。
WCF 服务器
这里我们通过等待来模拟一个冗长的操作,但是我们没有使用 Task
-aware 的 Sleep
,而是使用一个可等待的操作 Task.Delay
。
Task<string> async GetDataAsync (string text)
{
await Task.Delay (Timespan.FromSeconds(5));
return text + " processed";
}
所以我已经实现了客户端 EXE 和服务器 EXE 之间的本地主机 WCF 命名管道通信。我可以通过本地主机在服务器上调用 class 方法。所以,它就像一个 IPC/RPC。但是,如果服务器的 class 方法需要很长时间才能执行,那么我最好将其放入线程中,以便服务器 class 方法完成并在后台运行该线程。好的,很好,但是当线程完成其长期任务时,我想提醒客户端,而不必在客户端上使用计时器来检查 class 方法。计时器触发 class 方法比触发事件效率低得多。这就像我需要从服务器在客户端上引发一个事件。有没有一种简单的方法可以做到这一点或至少模拟它,而不需要做很多令人困惑的工作?
因此,假设您在 UI 中单击了一个按钮,该按钮在 WCF 服务上执行 WCF 同步方法调用,并且该同步方法需要很长时间才能 运行。显然,您不想在 运行ning 长任务执行期间阻止 UI 更新。自然地,您可能会考虑回调。例如,您调用服务器,服务器上的 class 方法生成一个线程并 运行s 该任务,完成后,它 returns 返回到通过回调客户端结果。
实际上,要在 WCF 上进行所有设置涉及许多复杂、令人困惑且记录不完整的步骤。但是有一种更简单的方法,它根本不涉及 WCF 代码,也不涉及您更改 WCF 服务上的任何内容,也不涉及编辑任何 WCF 配置。该技巧在 .NET 4.5 及更高版本中引入。它被称为 async
和 await
。这是一个单击按钮的示例,它调用 WCF 服务方法,该方法需要很长时间才能 运行 然后 return 完成后结果,但 GUI 没有t 锁定并可以处理其他事件。
1。首先,要模拟一个缓慢的任务,编辑您的 WCF 服务项目的共享 class 方法并在 return 结果之前添加此行,以便您可以模拟 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;
.
b。在您的按钮点击处理程序上将 private void...
更改为 private async void...
。
c。将 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 客户端项目中的按钮时,GetData() class 方法在后台线程中调用 WCF 服务项目,完成后,它会出现回到那个 await
语句和 returns 变量赋值的结果。在我的例子中,我点击了按钮,5 秒内没有任何反应——带有结果字符串的标签没有改变。但是,GUI 没有被锁定——我可以拖动 window,在其他字段中键入,单击其他表单按钮,等等。所以,它几乎就像一个回调事件处理程序,但不完全是。尽管如此,它仍然提供相同的功能,并且在大多数情况下可以用来代替回调事件处理程序。而且它涉及的代码少得多。
这是根据我对 OP 问题的评论得出的答案
你可以让你的 WCF 方法 asynchonous 然后这是一个简单的问题 async/await
或者完全取消 WCF 并使用内置异步 NamedPipeClientStream
(这仍然是等待兼容的)。更不用说在取消冗长的XML SOAP 编码
OP:
@MickyD You were right on the async/await thing now that I have studied that and implemented a test that works. That allows me to almost simulate a callback on a long running task and with minimal lines of code
例如以 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 完成端口和 "there is no thread" 中存在的 IOCP 哲学任务 I/O 绑定操作。因此,当我们通过 GetDataAsync
进行服务器调用时,我们不会浪费线程等待结果。
WCF 服务器
这里我们通过等待来模拟一个冗长的操作,但是我们没有使用 Task
-aware 的 Sleep
,而是使用一个可等待的操作 Task.Delay
。
Task<string> async GetDataAsync (string text)
{
await Task.Delay (Timespan.FromSeconds(5));
return text + " processed";
}