看看async,await 是如何简化异步的调用WCF!
A:调用WCF难吗?
B:不难
A:异步调用WCF难吗?
B:不难,
A:异步的调用WCF,并且需要保证异步的调用顺序难吗?
B:不难
A:那什么难?
B:异步的调用WCF,并且保证几个异步的调用顺序,并且代码的可读性,可维护性好,难。
为了演示这个过程,首先需要创建WCF服务应用程序。
废话不多说:
接口:
[ServiceContract]
public interface IService1
{
[OperationContract]
string Method1();
[OperationContract]
string Method2();
[OperationContract]
string Method3();
}
实现:
public class Service1 : IService1
{
public string Method1()
{
Thread.Sleep(2000);
return "method1";
}
public string Method2()
{
Thread.Sleep(50);
return "method2";
}
public string Method3()
{
Thread.Sleep(100);
return "method3";
}
}
浏览:
OK,WCF服务已经创建成功了。
现在需要创建Silverlight客户端来调用,之所以使用Silverlight,是因为Silverlight在生成的是异步调用WCF服务的代码。
首先创建Silverlight 应用程序,
修改MainPage.xaml 代码,在Grid中增加:
<Button Content="Third" Click="Third_Click" />
添加对服务的引用:
后台代码如下:
private void Third_Click(object sender, RoutedEventArgs e)
{
Service1Client service1 = new Service1Client();
service1.Method1Completed += (obj1, arg1) =>
{
MessageBox.Show(arg1.Result);
};
service1.Method1Async();
service1.Method2Completed += (obj2, arg2) =>
{
MessageBox.Show(arg2.Result);
};
service1.Method2Async();
service1.Method3Completed += (obj3, arg3) =>
{
MessageBox.Show(arg3.Result);
};
service1.Method3Async();
}
如你所想,
因为Method1 sleep 2000,Method2 sleep 50 ,Method3 sleep 100.
所以弹出来的分别是method2,method3,method1.
如果我想让执行顺序变为method1,method2,method3 ,那么该怎么办呢?
注意:执行顺序变为method1,method2,method3 的意思不是简单的MessageBox 的弹出顺序,它的意思是执行method1 后再执行method2,执行完method2后再执行method3. 后面不在赘述。
很简单,修改代码成这样就可以了,我相信很多同学都会写:
private void Third_Click(object sender, RoutedEventArgs e)
{
Service1Client service1 = new Service1Client();
service1.Method1Completed += (obj1, arg1) =>
{
MessageBox.Show(arg1.Result);
service1.Method2Completed += (obj2, arg2) =>
{
MessageBox.Show(arg2.Result);
service1.Method3Completed += (obj3, arg3) =>
{
MessageBox.Show(arg3.Result);
};
service1.Method3Async();
};
service1.Method2Async();
};
service1.Method1Async();
}
这段代码,主要是在每个callback里面才调用后面的方法。
这段代码没什么大的问题,唯一的缺点是嵌套太多,维护很复杂,如果中间的代码再多一点的话,维护会非常困难。
如果你用IService1接口的话,代码可能会是下面的样子:
private void Third_Click(object sender, RoutedEventArgs e)
{
IService1 service1 = new Service1Client();
service1.BeginMethod1(ar1 =>
{
Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(service1.EndMethod1(ar1));
service1.BeginMethod2(ar2 =>
{
Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(service1.EndMethod2(ar2));
service1.BeginMethod3(ar3 =>
{
Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(service1.EndMethod3(ar3));
});
}, null);
});
}, null);
});
}, null);
}
在这里MessageBox.Show 需要使用Dispatcher.BeginInvoke,否则会提示安全性错误。
Vs里面的截图是这样的:
这段代码比刚刚的代码更复杂,相信没有谁愿意维护这样的一大段代码的。
正是因为这种代码非常常见,但是却很复杂,微软推出了async await 关键字。
如果要使用async ,await,需要将vs 升级到sp1,并且下载安装AsyncCtp,在这里我假设大家都已经安装了扩展了。
如何使用,第一步需要在Silverlight 应用程序中添加对AsyncCtpLibrary_Silverlight 的引用。
一切准备就绪后,就可以使用async,await 了。
可以看到使用async ,await 代码的结构清晰了。
async 关键字表明Third_Click 是一个异步方法,这代表在方法中可以使用await来wait 一个task。
await 关键字代表等待task 的结束。
这段代码明显的表达了,在等待method1执行,接着等待method2执行,最后等待method3执行。
如果想要让method1 和method2 并行执行,method3 等待method1和method2 结束后才开始执行,那么又该如何呢?
横线代表方法的执行。
使用TaskEx.WhenAll 方法,让method1和method2 并行执行,使用await来等待任务的结果,
最后执行method3.
Method2 和method1 并行,两者结束后执行method3.
如果想让执行顺序变为method1 执行完后,method2和method3并行执行,那么该怎么办呢?
代码如下:
在这里使用Task.Factory.FromAsync得到一个task,接着await 这个task 得到method1执行的结果。
后面正常的调用就可以了。
默认弹出的是method1,method2,method3.如果将method2 的sleep时间变成Thread.Sleep(500).那么弹出的就是method1,method3,method2 了。
如果想等到所有结果后再弹出消息的话,那又该如何呢?:
最后出一道题目:
下面的代码
private void Third_Click(object sender, RoutedEventArgs e)
{
IService1 service1 = new Service1Client();
StringBuilder builder = new StringBuilder();
Task t = Task.Factory.FromAsync(service1.BeginMethod1(null, null),
(ar1) =>
{
builder.Append(service1.EndMethod1(ar1));
});
MessageBox.Show(
string.Format("{0},{1}", t.IsCompleted.ToString(), builder.ToString()));
}
弹出的消息是:
如何修改代码让弹出来的结果是这样子呢?,请使用async,await完成。