yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[上篇]
2013-04-12 20:56
761 查看
在定义API的时候,对于一些返回集合对象的方法,很多人喜欢将返回类型定义成IEnumerable<T>,这本没有什么问题。这里要说的是另一个问题:对于返回类型为IEnumerable<T>的方法来说,我们可以使用yield return的方式来输出返回集合的元素。但是如果我们不了解yield 关键字背后的实现机制,很有可能造成很大的问题。
这是一个WCF相关的问题,我想99%的人都有可能会犯这样的错误——即使你对yield了解得非常透彻。闲话少说,我们通过一个简单的实例来说明这个问题。我们定义了如下一个IDemoService接口作为服务契约,唯一的方法GetItems返回一个类型为IEnumerable<string>对象,并且具有唯一字符串参数category。
下面是实现了该契约接口的DemoService的实现:GetItems方法返回一个包含3个字符串的集合,但是在返回之前我们需要对参数实施验证。如果category参数提供的字符串为Null或者是空字符串,抛出一个FaultException异常并提示“Invalid Category”,这样客户端在输入不合法参数的情况下可以得到错误消息。这样的编程方式再正常不过了,不是吗?
可是正常并不意味着正确,客户端其实根本无法得到服务端提供给它的错误消息,如下所示的是客户端调用服务时指定一个空字符串参数情况下得到的错误。一个CommunicationException异常被抛出来,得到的错误消息为“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.”
这貌似和我们预期的效果不一样,我们希望的是客户端抛出一个FaultException,并提示“Invalid category”。这实际上就是因为“yield”在作祟,不相信的话可以将定义在DemoService的GetItems方法替换成如下的定义,即直接返回一个string[]对像。
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
再次运行我们的程序,这回可以得到我们期望的结果了。
有兴趣的朋友可以思考一下为什么两种貌似等效的方式为何会出现完全不同的结果,具体原因请看[下篇]。
yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[上篇]
yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[下篇]
这是一个WCF相关的问题,我想99%的人都有可能会犯这样的错误——即使你对yield了解得非常透彻。闲话少说,我们通过一个简单的实例来说明这个问题。我们定义了如下一个IDemoService接口作为服务契约,唯一的方法GetItems返回一个类型为IEnumerable<string>对象,并且具有唯一字符串参数category。
[ServiceContract] public interface IDemoService { [OperationContract] IEnumerable<string> GetItems(string category); }
下面是实现了该契约接口的DemoService的实现:GetItems方法返回一个包含3个字符串的集合,但是在返回之前我们需要对参数实施验证。如果category参数提供的字符串为Null或者是空字符串,抛出一个FaultException异常并提示“Invalid Category”,这样客户端在输入不合法参数的情况下可以得到错误消息。这样的编程方式再正常不过了,不是吗?
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"; } }
可是正常并不意味着正确,客户端其实根本无法得到服务端提供给它的错误消息,如下所示的是客户端调用服务时指定一个空字符串参数情况下得到的错误。一个CommunicationException异常被抛出来,得到的错误消息为“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.”
这貌似和我们预期的效果不一样,我们希望的是客户端抛出一个FaultException,并提示“Invalid category”。这实际上就是因为“yield”在作祟,不相信的话可以将定义在DemoService的GetItems方法替换成如下的定义,即直接返回一个string[]对像。
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" }; } }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
再次运行我们的程序,这回可以得到我们期望的结果了。
有兴趣的朋友可以思考一下为什么两种貌似等效的方式为何会出现完全不同的结果,具体原因请看[下篇]。
yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[上篇]
yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[下篇]
相关文章推荐
- yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[上篇]
- yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[下篇]
- yield在WCF中的错误使用——99%的开发人员都有可能犯的错误!
- yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[下篇]
- yield在WCF中的错误使用——99%的开发人员都有可能犯的错误[下篇]
- yield在WCF中的错误使用——99%的开发人员都有可能犯的错误!
- web开发各种乱码问题处理全集 保证解决99%的乱码错误(包括mysql的乱码解决,使用struts2框架的乱码问题)
- Python开发中有可能遇到的套接字重复使用错误
- 面向 Java 开发人员的 Ajax: 结合 Direct Web Remoting 使用 Ajax----数据序列化不可能比这更简单了!
- 【Android开发经验】LayoutInflater—— 你可能对它并不了解甚至错误使用
- 【Android开发经验】LayoutInflater—— 你可能对它并不了解甚至错误使用
- 使用F12开发人员工具调试JavaScript错误
- IE调试网页之五:使用 F12 开发人员工具调试 JavaScript 错误 (Windows)
- wcf 使用net.tcp 服务器未提供有意义的回复;这可能是由协定不匹配、会话过早关闭或内部服务器错误引起的
- wcf 使用net.tcp 服务器未提供有意义的回复;这可能是由协定不匹配、会话过早关闭或内部服务器错误引起的
- IE开发人员工具无法使用
- java开发人员需要注意的13个错误
- asp.net下的“Eval()、XPath() 和 Bind() 这类数据绑定方法只能在数据绑定控件的上下文中使用。”错误的一个可能的成因
- WCF开发实战系列四:使用Windows服务发布WCF服务
- Android 6.0 开发人员对系统权限的使用与练习(Permissions Best Practices)