EasyText, EasyLicense 的作者, https://github.com/EasyHelper Good Good Study,Day Day Up.

 

看看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";

    }

}

 

浏览:

image

OKWCF服务已经创建成功了。

 

现在需要创建Silverlight客户端来调用,之所以使用Silverlight,是因为Silverlight在生成的是异步调用WCF服务的代码。

 

首先创建Silverlight 应用程序,

 

修改MainPage.xaml 代码,在Grid中增加:

<Button Content="Third" Click="Third_Click" />

 

添加对服务的引用:

image

后台代码如下:

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里面的截图是这样的:

image

这段代码比刚刚的代码更复杂,相信没有谁愿意维护这样的一大段代码的。

 

正是因为这种代码非常常见,但是却很复杂,微软推出了async await 关键字。

如果要使用async await,需要将vs 升级到sp1,并且下载安装AsyncCtp,在这里我假设大家都已经安装了扩展了。

 

如何使用,第一步需要在Silverlight 应用程序中添加对AsyncCtpLibrary_Silverlight 的引用。

clip_image002

 

一切准备就绪后,就可以使用async,await 了。

image

可以看到使用async ,await 代码的结构清晰了。

async 关键字表明Third_Click 是一个异步方法,这代表在方法中可以使用awaitwait 一个task

await 关键字代表等待task 的结束。

这段代码明显的表达了,在等待method1执行,接着等待method2执行,最后等待method3执行。

 

 

如果想要让method1 method2 并行执行,method3 等待method1method2 结束后才开始执行,那么又该如何呢?

横线代表方法的执行。

clip_image006

image

使用TaskEx.WhenAll 方法,让method1method2 并行执行,使用await来等待任务的结果,

最后执行method3.

Method2 method1 并行,两者结束后执行method3.

 

如果想让执行顺序变为method1 执行完后,method2method3并行执行,那么该怎么办呢?

clip_image010

代码如下:

image 

 

在这里使用Task.Factory.FromAsync得到一个task,接着await 这个task 得到method1执行的结果。

后面正常的调用就可以了。

 

默认弹出的是method1,method2,method3.如果将method2 sleep时间变成Thread.Sleep(500).那么弹出的就是method1,method3,method2 了。

 

如果想等到所有结果后再弹出消息的话,那又该如何呢?:

image

clip_image016

 

最后出一道题目:

下面的代码

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()));

}

 

弹出的消息是:

clip_image018

 

如何修改代码让弹出来的结果是这样子呢?,请使用async,await完成。

clip_image020

posted @ 2012-03-16 09:45  LoveJenny  阅读(4926)  评论(8编辑  收藏  举报
EasyText, EasyLicense 的作者, https://github.com/EasyHelper Good Good Study,Day Day Up.