C# yield在WCF中的錯(cuò)誤用法(一)
在定義API的時(shí)候,對(duì)于一些返回集合對(duì)象的方法,很多人喜歡將返回類(lèi)型定義成IEnumerable<T>,這本沒(méi)有什么問(wèn)題。這里要說(shuō)的是另一個(gè)問(wèn)題:對(duì)于返回類(lèi)型為IEnumerable<T>的方法來(lái)說(shuō),我們可以使用yield return的方式來(lái)輸出返回集合的元素。但是如果我們不了解yield 關(guān)鍵字背后的實(shí)現(xiàn)機(jī)制,很有可能造成很大的問(wèn)題。
這是一個(gè)WCF相關(guān)的問(wèn)題,我想99%的人都有可能會(huì)犯這樣的錯(cuò)誤——即使你對(duì)yield了解得非常透徹。閑話少說(shuō),我們通過(guò)一個(gè)簡(jiǎn)單的實(shí)例來(lái)說(shuō)明這個(gè)問(wèn)題。我們定義了如下一個(gè)IDemoService接口作為服務(wù)契約,唯一的方法GetItems返回一個(gè)類(lèi)型為IEnumerable<string>對(duì)象,并且具有唯一字符串參數(shù)category。
[ServiceContract]
public interface IDemoService
{
[OperationContract]
IEnumerable<string> GetItems(string category);
}
下面是實(shí)現(xiàn)了該契約接口的DemoService的實(shí)現(xiàn):GetItems方法返回一個(gè)包含3個(gè)字符串的集合,但是在返回之前我們需要對(duì)參數(shù)實(shí)施驗(yàn)證。如果category參數(shù)提供的字符串為Null或者是空字符串,拋出一個(gè)FaultException異常并提示“Invalid Category”,這樣客戶(hù)端在輸入不合法參數(shù)的情況下可以得到錯(cuò)誤消息。這樣的編程方式再正常不過(guò)了,不是嗎?
public class DemoService : IDemoService
{
public IEnumerable<string> GetItems(string categoty)
{
if (string.IsNullOrEmpty(categoty))
{
throw new FaultException("Invalid category");
}
yield return "Foo";
yield return "Bar";
yield return "Baz";
}
}
可是正常并不意味著正確,客戶(hù)端其實(shí)根本無(wú)法得到服務(wù)端提供給它的錯(cuò)誤消息,如下所示的是客戶(hù)端調(diào)用服務(wù)時(shí)指定一個(gè)空字符串參數(shù)情況下得到的錯(cuò)誤。一個(gè)CommunicationException異常被拋出來(lái),得到的錯(cuò)誤消息為“An error occurred while receiving the HTTP response to http://127.0.0.1:3721/demoservice. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details.”

這貌似和我們預(yù)期的效果不一樣,我們希望的是客戶(hù)端拋出一個(gè)FaultException,并提示“Invalid category”。這實(shí)際上就是因?yàn)椤皔ield”在作祟,不相信的話可以將定義在DemoService的GetItems方法替換成如下的定義,即直接返回一個(gè)string[]對(duì)像。
public class DemoService : IDemoService
{
public IEnumerable<string> GetItems(string categoty)
{
if (string.IsNullOrEmpty(categoty))
{
throw new FaultException("Invalid category");
}
return new string[] { "Foo", "Bar", "Baz" };
}
}
再次運(yùn)行我們的程序,這回可以得到我們期望的結(jié)果了。

有興趣的朋友可以思考一下為什么兩種貌似等效的方式為何會(huì)出現(xiàn)完全不同的結(jié)果,具體原因請(qǐng)看[下篇]。
相關(guān)文章
C# Record構(gòu)造函數(shù)的行為更改詳解
C# 9 中的record類(lèi)型是僅具有只讀屬性的輕量級(jí)、不可變數(shù)據(jù)類(lèi)型(或輕量級(jí)類(lèi)),下面這篇文章主要給大家介紹了關(guān)于C# Record構(gòu)造函數(shù)的行為更改的相關(guān)資料,需要的朋友可以參考下2021-08-08
C#常用數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組Array
這篇文章介紹了C#常用數(shù)據(jù)結(jié)構(gòu)之?dāng)?shù)組Array,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05
Unity 實(shí)現(xiàn)給物體替換材質(zhì)球
這篇文章主要介紹了Unity 實(shí)現(xiàn)給物體替換材質(zhì)球的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-04-04
C#中DataSet,DataTable,DataView的區(qū)別與用法
這篇文章介紹了C#中DataSet,DataTable,DataView的區(qū)別與用法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05
C#使用itextsharp生成PDF文件的實(shí)現(xiàn)代碼
以下是對(duì)在C#中使用itextsharp生成PDF文件的實(shí)現(xiàn)代碼進(jìn)行了詳細(xì)分析介紹,需要的朋友可以過(guò)來(lái)參考下2013-07-07
C#實(shí)現(xiàn)將應(yīng)用程序設(shè)置為開(kāi)機(jī)啟動(dòng)的方法
這篇文章主要介紹了C#實(shí)現(xiàn)將應(yīng)用程序設(shè)置為開(kāi)機(jī)啟動(dòng)的方法,涉及C#針對(duì)注冊(cè)表的寫(xiě)入技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09
Unity性能優(yōu)化Shader函數(shù)ShaderUtil.GetShaderGlobalKeywords用法示例
這篇文章主要為大家介紹了Unity性能優(yōu)化Shader函數(shù)ShaderUtil.GetShaderGlobalKeywords用法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
Unity3D開(kāi)發(fā)教程:憤怒的小鳥(niǎo)
這篇文章詳細(xì)的講解了如何從0開(kāi)發(fā)出一個(gè)Unity3D的小游戲憤怒的小鳥(niǎo),本文包含大量的圖片與文字描述,也含有大量的源代碼,可以讓你快速入手,希望本篇文章對(duì)你有所幫助2021-06-06

