Effective Error Handling with WCF & REST(WCF REST Service 高效错误处理)
2012-05-10 13:53
405 查看
转自:http://www.robbagby.com/rest/effective-error-handling-with-wcf-rest/, the author explained how to deal with error handling case for WCF REST Service, thanks!
I recently received a question regarding effective error handling when working with RESTful web services. In this post, I will illustrate how to expose, as well as handle errors effectively when working with RESTful WFC services.
As you can see from the ServiceHost directive, we are using the configurationless model. By setting the factory to WebServiceHostFactory, we do not need to define all of the configuration settings in the web.config under System.serviceModel. The WebServiceHostFactory
will dynamically set up an instance of the WebServiceHost in response to requests. The WebServiceHost will set up a default endpoint, if appropriate, with the binding set to webHttpBinding (read REST-Friendly binding). Further, this host will add the WebHttpBehavior
to the endpoints. The WebServiceHostFactory is our RESTful factory and first shipped with WCF 3.5 (with Visual Studio 2008 sp1).
Examining the service implementation, it is clear that this is a relatively simple service operation that we are exposing. The operation returns a page of wines from our wine catalog (by page, I am referring to returning a subset of wines (1 to x out of
y) instead of the complete set). We decorated the operation with a WebGet, exposing the service over an HTTP GET. We further set the ResponseFormat to JSON and set up a friendly UriTemplate. If the above concepts are foreign to you, or you want a refresher
on the basics of REST in WCF,
check out all of my blog posts on the subject. The last thing to notice is that if someone passes an invalid pageSize, we are throwing an ApplicationException. This is what you might expect to see in a typical .NET implementation. The next step is to
cover the basics of errors in RESTful services.
200: OK, 404: Not Found: 400: Bad Request and 500: Internal Server Error. What you may not know is that the codes are logically grouped as follows:
100-199 – Informational
200-299 – Client request successful
300-399 – Client request redirected, further action necessary
400-499 – Client request incomplete
500-599 – Server error
The appropriate status code is returned to the requestor as an HTTP header, allowing the requestor to determine the result of the call. The response can optionally contain additional information in the response body. We will see some examples of this in
this post.
WCF REST Starter Kit is a toolkit that provides Visual Studio templates, samples and a dll (Microsoft.ServiceModel.Web.dll) that provides some great functionality. In this post, we will examine some of the types made available in Microsoft.ServiceModel.Web.dll,
including the WebServiceHost2Factory, the WebServiceHost2 and a new exception type named the WebProtocolException. To take advantage of the factory and new ServiceHost, you simply need to set a reference to the assembly in your web and set the Factory in
the svc file to the new factory (see below). This factory will return instances of the WebServiceHost2 in response to requests. As we will see later in this post, the WebServiceHost2 provides some cool new functionality (as well as changes some default behaviors).
Click
here to download the starter kit.
can see that is exactly what I am doing. So, let’s take a look at the resulting HTTP status code using both of our ServiceHosts (WebServiceHost via the WebServiceHostFactory and WebServiceHost2 via the WebServiceHost2Factory). The results should be the same,
right?
All tests are using the same request url: http://robagby1:46000/Web/WineService.svc/wines?index=0&pageSize=-1
Test 1: Throwing an ApplictionException with the WebServiceHost
Setup:
Result:
Test 2: Throwing an ApplictionException with the WebServiceHost2
Setup:
(code is same as in Test 1)
Result:
As you can see, the two tests returned with differing HTTP Status Codes. The first returned a 400, which is probably the correct code to return. It is telling the requestor that they issued a “Bad Request” for some reason or another. Unfortunately, the
error detail would provide little help to the caller what the issue really was. The second test returned a 500, telling the caller that there was an “Internal Server Error”. This would leave the caller thinking that the issue was not with their request,
rather with the code on the server. That would be bad. However, the error detail would have been helpful. As you can see, it is a JSON formatted body. The JSON represents an object with one property named “Detail” and the value of the property is “pageSize
must be > 0”.
This simple test illustrates that you never want to rely on defaults. They can and do change. What we learned here is that we want to be explicit on what HTTP status code to return. We also (may) want to include some appropriate error details. Let’s
take a look at some other, more explicit, solutions.
of the Request and Response. In this case, we grabbed a reference to the Response. If the pageSize was less than or equal to 0, we explicitly set the status code of the response to 400, or “Bad Request”. We, however did not send any response. Let’s take
a look at the code:
Setup:
Result:
As you can see, using this methodology, we are able to force the appropriate HTTP Status Code. However, we still do not have the capability to easily send additional error details. Let’s move on to another solution, taking advantage of the WebServiceHost2.
of the format of the response. If the ResponseFormat is set to Json, the details should be serialized as Json. If it is Xml, it should be serialized as Xml, perhaps XHtml, so it is pleasant to see in the browser. The
WCF REST Starter Kit handles all of this for us. All we need to do is to set the Factory to the WebServiceHost2Factory (or implement our own factory) that will return instances of WebServiceHost2. Then we just need to throw our new Exception type: the
WebProtocolException. This new type takes the Status Code, as well as the details as an argument. The Status Code will be set on the response and the detail will be serialized according to the RespinseFormat that was set on the operation. Let’s take a look:
Setup:
Result:
Eugene Osotevsky’s blog post on the subject.
WCF REST Starter Kit provides all of these capabilities with great ease.
I recently received a question regarding effective error handling when working with RESTful web services. In this post, I will illustrate how to expose, as well as handle errors effectively when working with RESTful WFC services.
Watch the Screencast
Watch the screencast on Channel9.The Sample Service
As you can see from the ServiceHost directive, we are using the configurationless model. By setting the factory to WebServiceHostFactory, we do not need to define all of the configuration settings in the web.config under System.serviceModel. The WebServiceHostFactory
will dynamically set up an instance of the WebServiceHost in response to requests. The WebServiceHost will set up a default endpoint, if appropriate, with the binding set to webHttpBinding (read REST-Friendly binding). Further, this host will add the WebHttpBehavior
to the endpoints. The WebServiceHostFactory is our RESTful factory and first shipped with WCF 3.5 (with Visual Studio 2008 sp1).
Examining the service implementation, it is clear that this is a relatively simple service operation that we are exposing. The operation returns a page of wines from our wine catalog (by page, I am referring to returning a subset of wines (1 to x out of
y) instead of the complete set). We decorated the operation with a WebGet, exposing the service over an HTTP GET. We further set the ResponseFormat to JSON and set up a friendly UriTemplate. If the above concepts are foreign to you, or you want a refresher
on the basics of REST in WCF,
check out all of my blog posts on the subject. The last thing to notice is that if someone passes an invalid pageSize, we are throwing an ApplicationException. This is what you might expect to see in a typical .NET implementation. The next step is to
cover the basics of errors in RESTful services.
REST and Errors
As you probably know, the underlying theme of REST is to embrace the key protocols of the web. The means in which a successful or failed call is conveyed to the requestor in HTTP is via an HTTP status code. We are all familiar with at least a few of these:200: OK, 404: Not Found: 400: Bad Request and 500: Internal Server Error. What you may not know is that the codes are logically grouped as follows:
100-199 – Informational
200-299 – Client request successful
300-399 – Client request redirected, further action necessary
400-499 – Client request incomplete
500-599 – Server error
The appropriate status code is returned to the requestor as an HTTP header, allowing the requestor to determine the result of the call. The response can optionally contain additional information in the response body. We will see some examples of this in
this post.
The WCF REST Starter Kit
TheWCF REST Starter Kit is a toolkit that provides Visual Studio templates, samples and a dll (Microsoft.ServiceModel.Web.dll) that provides some great functionality. In this post, we will examine some of the types made available in Microsoft.ServiceModel.Web.dll,
including the WebServiceHost2Factory, the WebServiceHost2 and a new exception type named the WebProtocolException. To take advantage of the factory and new ServiceHost, you simply need to set a reference to the assembly in your web and set the Factory in
the svc file to the new factory (see below). This factory will return instances of the WebServiceHost2 in response to requests. As we will see later in this post, the WebServiceHost2 provides some cool new functionality (as well as changes some default behaviors).
Click
here to download the starter kit.
Throwing Exceptions in .NET
Well, the first thing I want to look at is what happens if I do nothing. In other words, what is the behavior if I just let .NET exceptions propagate up or I just throw a .NET exception like an ApplicationException. Taking a look at the code above, youcan see that is exactly what I am doing. So, let’s take a look at the resulting HTTP status code using both of our ServiceHosts (WebServiceHost via the WebServiceHostFactory and WebServiceHost2 via the WebServiceHost2Factory). The results should be the same,
right?
All tests are using the same request url: http://robagby1:46000/Web/WineService.svc/wines?index=0&pageSize=-1
Test 1: Throwing an ApplictionException with the WebServiceHost
Setup:
Result:
Test 2: Throwing an ApplictionException with the WebServiceHost2
Setup:
(code is same as in Test 1)
Result:
As you can see, the two tests returned with differing HTTP Status Codes. The first returned a 400, which is probably the correct code to return. It is telling the requestor that they issued a “Bad Request” for some reason or another. Unfortunately, the
error detail would provide little help to the caller what the issue really was. The second test returned a 500, telling the caller that there was an “Internal Server Error”. This would leave the caller thinking that the issue was not with their request,
rather with the code on the server. That would be bad. However, the error detail would have been helpful. As you can see, it is a JSON formatted body. The JSON represents an object with one property named “Detail” and the value of the property is “pageSize
must be > 0”.
This simple test illustrates that you never want to rely on defaults. They can and do change. What we learned here is that we want to be explicit on what HTTP status code to return. We also (may) want to include some appropriate error details. Let’s
take a look at some other, more explicit, solutions.
Setting the Status Code On The Response
On solution is to get a reference to the response and set the HTTP Status Code yourself. That solution works with the original WebServiceHost that shipped with WCF 3.5. There is a helper object named WebOperationContext that provides access to the propertiesof the Request and Response. In this case, we grabbed a reference to the Response. If the pageSize was less than or equal to 0, we explicitly set the status code of the response to 400, or “Bad Request”. We, however did not send any response. Let’s take
a look at the code:
Setup:
Result:
As you can see, using this methodology, we are able to force the appropriate HTTP Status Code. However, we still do not have the capability to easily send additional error details. Let’s move on to another solution, taking advantage of the WebServiceHost2.
Throwing a WebProtocolException with WebServiceHost2
There is a way to get the best of all worlds: the ability to control the HTTP Status Code, as well as to pass additional error details. Interestingly enough, passing the error details is more complex than you might originally think. You need to be awareof the format of the response. If the ResponseFormat is set to Json, the details should be serialized as Json. If it is Xml, it should be serialized as Xml, perhaps XHtml, so it is pleasant to see in the browser. The
WCF REST Starter Kit handles all of this for us. All we need to do is to set the Factory to the WebServiceHost2Factory (or implement our own factory) that will return instances of WebServiceHost2. Then we just need to throw our new Exception type: the
WebProtocolException. This new type takes the Status Code, as well as the details as an argument. The Status Code will be set on the response and the detail will be serialized according to the RespinseFormat that was set on the operation. Let’s take a look:
Setup:
Result:
Silverlight
Handling service errors from Silverlight uncovers a unique set of problems. Because Silverlight is a plugin, the browser will hide the actual status code and error detail from the client. Take a look atEugene Osotevsky’s blog post on the subject.
Conclusion
Your RESTful services should return the appropriate HTTP Status Code in the response. You may also want to pass back some additional error detail. TheWCF REST Starter Kit provides all of these capabilities with great ease.
相关文章推荐
- An internal error occurred during: "Items filtering". Class file name must end with .class。错误处理
- Scala新手指南中文版 -第六篇 Error Handling with Try(用Try来处理错误)
- WCF RIA Service错误处理
- 【WCF】自定义错误处理(IErrorHandler接口的用法)
- Error:Execution failed for task ':app:compileDebugJavaWithJavac'. > Compilation failed; 奇怪错误
- Python使用pip install psycopg2安装psycopg2包出现python setup.py egg_info failed with error code 1 in /tmp/pip-build-YtLeN3/psycopg2错误处理
- 错误处理(Error-Handling):为何、何时、如何(rev#2)
- "nova service-list ERROR (ClientException)错误处理"
- 关于wcf异常异常信息:由于内部错误,服务器无法处理该请求。有关该错误的详细信息,请打开服务器上的 IncludeExceptionDetailInFaults (从 ServiceBehaviorAttribut
- (6)LUA程序设计-编译执行与错误(compile 、run & error)处理
- 【WCF】错误处理(四):一刀切——IErrorHandler
- windows 安装mysql出现 could not start the service mysql error:0 错误处理
- 错误处理(Error-Handling):为何、何时、如何(rev#2)
- bean依赖注入错误:Error creating bean with name 'itemService': Injection of autowired dependencies failed
- SSH搭建时的错误之(1) Error creating bean with name 'testService' defined in class path resource
- MySQL-python “error: command 'gcc' failed with exit status 1”错误
- OpenStack常见错误:无法开启http服务 Job for httpd.service failed because the control process exited with error
- PHP - Manual手册 - XXXIII. Error Handling and Logging Functions错误处理和日志函数 - 概述
- MPSENG上 "MPFTranLogData with error code 80004005. "错误的处理
- 错误处理(Error-Handling):为何、何时、如何