我有这个项目:- 在控制台应用程序中托管的 WCF 服务(基本 HttpBinding)- 为我的合同分离 PCL 库- WPF 客户端- Xamarin.Forms (便携式) - 三个移动客户端。
在 WCF 中,我有异步服务,我想在每个客户端中使用它。这是我的第一个问题:PCL 不支持客户端的 TAP(基于任务的异步模式)。在PCL中,我只能以IAsyncResult Begin/End样式执行APM(异步编程模型)。让我展示我的代码:
这是我的 WCF 服务:
[ServiceContract]
public interface ICalculatorService
{
[OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetSum(int a, int b, AsyncCallback callback, object state);
string EndGetSum(IAsyncResult asyncResult);
}
public class CalculatorService : ICalculatorService
{
private Task<string> GetSum(int a, int b)
{
return Task.Factory.StartNew(() => (a+ b).ToString());
}
public IAsyncResult BeginGetSum(int a, int b, AsyncCallback callback, object state)
{
var tcs = new TaskCompletionSource<string>(state);
var task = GetSum(a, b);
task.ContinueWith(t =>
{
if (t.IsFaulted)
tcs.TrySetException(t.Exception.InnerExceptions);
else if (t.IsCanceled)
tcs.TrySetCanceled();
else
tcs.TrySetResult(t.Result);
if (callback != null)
callback(tcs.Task);
});
return tcs.Task;
}
public string EndGetSum(IAsyncResult asyncResult)
{
try
{
return ((Task<string>)asyncResult).Result;
}
catch (AggregateException ex)
{
throw ex.InnerException;
}
}
}
和主机配置:
<system.serviceModel>
<services>
<service name="MobileWCF.ServerHost.CalculatorService">
<endpoint address="http://localhost:9003/CalculatorService" binding="basicHttpBinding"
contract="MobileWCF.Contracts.ICalculatorService" />
</service>
</services>
</system.serviceModel>
在每个客户端(Xamarin.Froms 和 WPF)中,我都使用它,如下所示:
private void bConnect_Click(object sender, EventArgs e)
{
string strAddress = "http://localhost:9003/CalculatorService";
BasicHttpBinding httpBinding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress(strAddress);
ChannelFactory<ICalculatorService> channel = new ChannelFactory<ICalculatorService>(httpBinding, address);
var game = channel.CreateChannel(address);
var num = game.BeginGetSum(4, 1, Callback, game);
}
private void Callback(IAsyncResult result)
{
var res = result.AsyncState as ICalculatorService;
if (res != null)
Debug.Write(res.EndGetSum(result));
}
我的问题是:在像WPF或WinForms这样的客户端上,我想像这样使用它: await service.GetSum(1, 2);
async await
风格。
问题是:我应该如何实现我的 WCF 协定和服务实现,以便能够在 Xamarin.Forms 客户端中的开始/结束 APM 样式中使用它,并在 WPF 或 WinForms 程序中以异步等待 TAP 样式使用它?
如果您仍在寻找答案,实际上很容易。如果您查看Task.Factory
您将看到一个名为 FromAsync<>()
的帮助程序方法,它完全可以执行您想要的操作。Xamarin 窗体中的客户端代码如下所示:
private async void bConnect_Click(object sender, EventArgs e)
{
string strAddress = "http://localhost:9003/CalculatorService";
BasicHttpBinding httpBinding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress(strAddress);
ChannelFactory<ICalculatorService> channel = new ChannelFactory<ICalculatorService>(httpBinding, address);
var game = channel.CreateChannel(address);
string num =
await Task.Factory.FromAsync<int, int, string> (
game.BeginGetSum,
game.EndGetSum,
4, 1,
null);
Debug.Write(num);
}
请注意,我将 Click 处理程序的签名更改为 async void
以启用异步/等待语法。
主要要点是,FromAsync<>()
为您提供了一种将一对 APM 开始/结束方法签名包装到可等待的 TPL Task 对象中的简单方法。
请试一试。如果你已经继续前进了(这个问题现在已经有一周了),那么至少把它放在你的脑海中,以备下次使用。