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完成。