Exception handling with WCF Data Services - exception

I want to customize exceptions/errors thrown from my WCF Data Service, so clients get as much as possible information about what exactly went wrong/what is missing. Any thoughts on how this could be achieved?

There are a few things you need to do to ensure exceptions bubble over HTTP pipe to the client .
You must attribute your DataService class with the following:
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class MyDataService : DataService
You must enable verbose errors in the configuration:
public static void InitializeService(DataServiceConfiguration config)
{
config.UseVerboseErrors = true;
}
It is best to throw DataServiceException within. The WCF Data Service runtime knows how to map the properties to the HTTP response and will always wrap it in a TargetInvocationException.
[WebGet]
public Entity OperationName(string id)
{
try
{
//validate param
Guid entityId;
if (!Guid.TryParse(id, out entityId))
throw new ArgumentException("Unable to parse to type Guid", "id");
//operation code
}
catch (ArgumentException ex)
{
throw new DataServiceException(400, "Code", ex.Message, string.Empty, ex);
}
}
You can then unpack this for the client consumer by overriding the HandleException in your DataService like so:
/// <summary>
/// Unpack exceptions to the consumer
/// </summary>
/// <param name="args"></param>
protected override void HandleException(HandleExceptionArgs args)
{
if ((args.Exception is TargetInvocationException) && args.Exception.InnerException != null)
{
if (args.Exception.InnerException is DataServiceException)
args.Exception = args.Exception.InnerException as DataServiceException;
else
args.Exception = new DataServiceException(400, args.Exception.InnerException.Message);
}
}
See here for more info...

You can decorate your service class with this attribute ServiceBehaviorAttribute like so :
[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
public class PricingDataService : DataService<ObjectContext>, IDisposable
{
...
}

You need to create custom exceptions for this.
Please read this post here: Why Create Custom Exceptions?
Which language are you developing in?
If you need further guidance, please add some comments.

I don't think he wants to know how to throw / catch exceptions in .NET.
He probably want to get thoughts on how to tell the clients consuming a WCF Data Service that something (and what) went wrong when an exception is being thrown / caught at the server(service) side.
WCF Data Services uses HTTP request / response messages and you can't just throw an exception from the service to the client.

Related

Jersey ParamConverter exceptions not handled by ExceptionMapper

Per title, exceptions thrown from a ParamConverter are NOT handled the way I expect.
With an ExceptionMapper:
#Provider
public class MyExceptionMapper implements ExceptionMapper<MyException> {
#Override
public Response toResponse(MyException exception) {
return Response.serverError().entity( "It triggered" ).build();
}
}
and ParamConverter:
#Provider
(boilerplate junk)
#Override
public DateTime fromString(String value) {
throw new MyException("convert");
}
It does NOT return the "It triggered" text in a 500 error, but rather a 404.
Anticipated question : Are both providers registered?
Yes - If I throw "MyException" from a resource (within 'regular' code) it works as expected. I can also convert see the stacktrace with the "convert" message.
Is there any way to make exceptions from ParamConverters be handled by the ExceptionMapper?
I am using jersey 2.3.1, along with spring-jersey, launched in a jetty container 9.1.0.RC0
Seem from reading this, the JAX-RS spec says the implementor should wrap unhandled exceptions in a NotFoundException (404) for #QueryParam and #PathParam, and from what I tested a 400, (I'm guessing BadRequestException) for #FormParam.
"if the field or property is annotated with #MatrixParam, #QueryParam or #PathParam then an implementation MUST generate an instance of
NotFoundException (404 status) that wraps the thrown exception and no entity"
A couple ways I can see handling the exception, is to
Just handle it in the ParamConverter, e.g.
return new ParamConverter<T>() {
#Override
public T fromString(String string) {
try {
return (T)new MyObject().setValue(string);
} catch (MyException ex) {
Response response = Response.serverError().entity("Boo").build()
throw new WebApplicationException(response);
}
}
#Override
public String toString(T t) {
return t.toString();
}
};
Or just have your exception extend WebApplicationException, and return the Response there. e.g.
public class MyException extends WebApplicationException {
public MyException(String message) {
super(Response.serverError().entity(message).build());
}
}
I experienced the same behavior in Jersey 2.26.
Any Exception that extends RuntimeException gets mapped to a ParamException, which is itself a sublcass of WebApplicationException.
Assuming your MyException extends RuntimeException, it's not getting caught because your ExceptionMapper only handles MyException.
Regarding the Jersey docs saying to throw a NotFoundException: I would argue a 404 does not apply when a queryParam can't be converted. A BadRequestException seems more appropriate. And also, I can't see anything unique in the Jersey frame work when a NotFoundException is thrown besides setting the response code
To get exceptions thrown from a ParamConverter end up in an ExceptionMapper, you'll have to have your ExceptionMapper catching a more global exception, like Throwable.
Another answer suggests returning a WebApplicationException. This should be a fine solution but will NOT work if the Response object has an entity. See here: https://github.com/jersey/jersey/issues/3716

Call a Rest method with mockito

I use Jersey and I have the following Rest function which returns a JSON string when my server is deployed:
#GET
#Path("getallemployees")
#Produces("application/json")
public Response getAllEmployees() {
//building the entity object which is List<Employee>
return Response.ok(entity).build();
}
I need to develop some unit tests (not integration testing) and I want to somehow mock the HTTPRequest that invokes this method and then get the json String. The best option would be to use mockito for this.
Is there any suggestion on how to do it ?
Thanks !!
The problem is that the method returns a Response object to the caller which is deep within the framework code. It doesn't return JSON strings.
You can use Mockito, if you need to mock something inside the method itself. That should work.
But you may need to take the value returned by the method and convert it to JSON like this if you are using Jackson with Jersey.
Response response = getAllEmployees();
Object retval = response.getEntity();
try {
ObjectMapper mapper = new ObjectMapper();
// I like this formatting. You can change it.
mapper.configure(Feature.INDENT_OUTPUT, true);
mapper.configure(Feature.WRITE_ENUMS_USING_TO_STRING, true);
mapper.configure(Feature.USE_ANNOTATIONS, false);
mapper.configure(Feature.FAIL_ON_EMPTY_BEANS, false);
mapper.setSerializationInclusion(Inclusion.NON_NULL);
mapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
mapper.getSerializationConfig().withSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
String json = mapper.writeValueAsString(retval);
... assert something about the string
} catch (JsonProcessingException e) {
// do something
} catch (IOException e) {
// do something
}
Some of this is guess work and speculation on my part but it may help. You could try using the Jersey Test Framework with the InMemoryTestContainerFactory:
It starts Jersey application and directly calls internal APIs to handle request created by client provided by test framework. There is no network communication involved. This containers does not support servlet and other container dependent features, but it is a perfect choice for simple unit tests.
It looks like to use it, all you need to do is extend JerseyTest and then override getTestContainerFactory() and follow the rest of the instructions, e.g.:
public class EmployeeResourceTest extends JerseyTest {
#Override
protected Application configure() {
// set up employee resource with mock dependencies etc...
return new ResourceConfig().registerInstances(employeeResource);
}
#Test
public void getAllEmployees() {
final String response = target("getallemployees").request().get(String.class);
// assert etc...
}
}
I used registerInstances instead of registerClasses in configure() as it looks like you can present a ready made Resource but set up with any mock dependencies you may want - although I haven't tried this myself.
The test class is a bit inflexible as you can only do one-time set up of dependencies in the configure() method, so it might be worth investigating using the MockitoJUnitRunner - although I'm not sure if it will work with the JerseyTest inheritance. It could allow you to do add behaviour to mocks in each #Test method, e.g.:
#Mock
private EmployeeResourceDependency dependency;
#InjectMocks
private EmployeeResource employeeResource;
// configure() as above but without mock setup up etc...
#Test
public void getAllEmployees() {
given(dependency.getEmployees()).willReturn(...);
// etc...
But like I said it might not be possible to mix them at all.

NO JSON Result from Spring3 MVC DispatcherServlet due to AOP Configuration

When we configure Spring AOP the JSON Results disappear for : AOPExression1
<aop:pointcut id="dmhMethodExecution"
expression="within(com.aditya.dmh..*)" />
So I added an exclusion for : AOPExpression1 as AOpExpression2
<aop:pointcut id="dmhMethodExecution"
expression="within(com.aditya.dmh..*)
and !within(com.aditya.dmh.controller..*)" />
in the ASPECTJ Expression
Still I donot see my JSON results from the controller which is a restful implementation.
package com.aditya.dmh.controller;
#Controller
public class EmployeeController {
private EmployeeServiceInterface employeeService;
#Autowired
public void setEmployeeService(EmployeeServiceInterface employeeService) {
this.employeeService = employeeService;
}
#RequestMapping("/employeeservices/1/allemployees.view")
public #ResponseBody Result<EmployeeModel> getEmployees(){
return employeeService.getEmployees(0, 10);
}
}
When I use log4j for the DEBUG messages I see the following:
15:37:04.214 [http-8090-1] DEBUG o.s.web.servlet.DispatcherServlet - Null ModelAndView returned to DispatcherServlet with name 'dmhServiceDispatcher': assuming HandlerAdapter completed request handling
15:37:04.214 [http-8090-1] DEBUG o.s.web.servlet.DispatcherServlet - Successfully completed request
When I remove the AOP the JSON results start to appear and I see that the additional Debug Message.
17:11:36.270 [http-8090-2] DEBUG o.s.w.s.m.m.a.RequestResponseBodyMethodProcessor - Written [com.aditya.Result#8a85268] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter#62ba2e48]
Looking at the Spring forums I understand that the Convertor is automatically configured when the
<mvc:annotation-driven/>
is used.
Is my problem of configuring AOP have anything to do with the RequestResponseBodymethodProcessor not being called.
Does this have anything to do with the proxies created around my controller when I use AOPExpression1. Why would an exclusion as in AOPExpression2 still have the problem.
Anyhelp would be appreciated
I belive that to intercept a request to a controller you should do it with MVC interceptors and not with aspects. What I did is to put into the applicationContext.xml this:
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/employeeservices/1/allemployees.view"/>
<bean class="com.aditya.dmh.interceptor.ResultInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
Now, the class ResultInterceptor is where you put the code you want to be done, for instance:
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("--- preHandle --- ");
return true;
}
At least this is the way I did it.
Hope it helps.
This is a bit of a speculation:
I think what is happening is a CGLIB based dynamic proxy is getting created for your controller (although you have excluded it explicitly in your new pointcut expression), if this happens then #RequestMapping annotations are not correctly detected(by `) and so the controller is not there to handle your REST request.
Can you try a few things:
Have an interface for the controller with the exact same methods that the controller handles, and put the #RequestMapping annotations there, this will handle cases where the dynamic proxy is created and should work as expected even if the dynamic proxy gets created..
Play around a little more with your pointcut expression to see why a proxy for you controller may be getting created.
THE SOLUTION FOR OUR PROBLEM IN THIS CONTEXT
We found out that the whole thing was with the Around Advice in AOP Configuration that we have had.
Before Fix
public void logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
joinPoint.proceed();
long totalTime = System.currentTimeMillis() - startTime;
log.debug(buildLogMessage(new StringBuilder().append(METHOD_AROUND_ID)
.append("[").append(totalTime).append("] ").toString(),
joinPoint));
return returnValue;
}
After Fix
public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
long startTime = System.currentTimeMillis();
Object returnValue = joinPoint.proceed();
long totalTime = System.currentTimeMillis() - startTime;
log.debug(buildLogMessage(new StringBuilder().append(METHOD_AROUND_ID)
.append("[").append(totalTime).append("] ").toString(),
joinPoint));
return returnValue;
}
the void effectively made sure that the Response Object sent by the logAround was not passed on back to the RequestResponseBodyMethodProcessor
Once we had it captured & returned the cglib proxies sent the response back to the processor & had the response sent back to the client.

Exception/MessageBox in Calibur.Micro

I start learning Caliburn.Micro and I am little confuse of handling with exception/messange box in view model class.
I found some blogs about, for example:
http://frankmao.com/2010/11/18/handling-messagebox-in-caliburn-micro/
For example some method in view model class which can produce exception.
public void MethodWichCanProduceEx(string arg1, string arg2 )
{
if(arg1==null)
throw new ArgumentNullException("arg1 is null");
if (arg2 == null)
throw new ArgumentNullException("arg2 is null");
try
{
}
catch (Exception exception)
{
throw exception;
//? show message box MessageBox.Shox(exception.Message)
}
}
What is correct handling and showing these exception in view ? It exist any kind of pattern for caliburn.micro?
It possible trace exception as in .NET in text, xml file ?
For example I would like trace exception in xml, text file and in view show only message.box or something message.
Thank for advance, maybe is my question little stupid, sorry I am only learning calibur.micro.
You'll want to always work against abstractions in your view models, in the case of message boxes, you don't want to have to wait for user input when you come to unit test your view models.
The Frank Mao code you linked to uses a delegate to abstract the implementation of the message box from the view model, but I would use an interface here. You can think of a delegate as an interface with a single method, but the advantage of using an interface in this context is that you can have different methods depending on the type of message you wish to show. For example, you could have a ShowMessageError, ShowMessageWarning, ShowMessageInfo etc.
So, define a contract for your message box:
public interface IMessageBox
{
void ShowException(Exception exc);
}
Inject the message box dependency into your view model, e.g. via the constructor
public class MyViewModel
{
private readonly IMessageBox messageBox;
public MyViewModel(IMessageBox messageBox)
{
this.messageBox = messageBox;
}
public void MethodThatCanThrowException()
{
try {}
catch(Exception exc)
{
// log the exception here
...
// show message box
this.messageBox.ShowException(exc);
}
}
}
You can then implement the message box anyway you wish, either using the windows system message box, or nicer still use your own view/viewmodel to display the message, perhaps using the Caliburn.Micro WindowManager.ShowDialog().
An implementation that uses the windows system message box may look like:
public class StandardMessageBox : IMessageBox
{
public void ShowException(Exception exception)
{
MessageBox.Show(exception.ToString(), "Error Occurred");
}
}
In production code, you can register StandardMessageBox against the IMessageBox interface in your IoC container.
In unit test land, you can mock out IMessageBox and have it do nothing, or in the case of methods with a result from the message box, always return a value you wish.
For logging the exception, I would look at a logging framework such as log4net (http://logging.apache.org/log4net/index.html) or NLog (http://nlog-project.org/)

GWT JsonpRequestBuilder Timeout issue

I am getting time out from using JsonpRequestBuilder.
The entry point code goes like this:
// private static final String SERVER_URL = "http://localhost:8094/data/view/";
private static final String SERVER_URL = "http://www.google.com/calendar/feeds/developer-calendar#google.com/public/full?alt=json-in-script&callback=insertAgenda&orderby=starttime&max-results=15&singleevents=true&sortorder=ascending&futureevents=true";
private static final String SERVER_ERROR = "An error occurred while "
+ "attempting to contact the server. Please check your network "
+ "connection and try again.";
/**
* This is the entry point method.
*/
public void onModuleLoad() {
JsonpRequestBuilder requestBuilder = new JsonpRequestBuilder();
// requestBuilder.setTimeout(10000);
requestBuilder.requestObject(SERVER_URL, new Jazz10RequestCallback());
}
class Jazz10RequestCallback implements AsyncCallback<Article> {
#Override
public void onFailure(Throwable caught) {
Window.alert("Failed to send the message: " + caught.getMessage());
}
#Override
public void onSuccess(Article result) {
// TODO Auto-generated method stub
Window.alert(result.toString());
}
The article class is simply:
import com.google.gwt.core.client.JavaScriptObject;
public class Article extends JavaScriptObject {
protected Article() {};
}
The gwt page, however, always hit the onFailure() callback and show this alert:
Failed to send the message. Timeout while calling <url>.
Fail to see anything on the Eclipse plugin console. I tried the url and it works perfectly.
Would appreciate any tip on debugging technique or suggestion
Maybe you should set the callback function explicitly via setCallbackParam, since you have callback=insertAgenda in your url - I presume that informs the server what should be the name of the callback function that wraps the JSON.
Also, it's worth checking Firebug's console (or a similar tool for your browser) - even if GWT doesn't report any exceptions, Firebug still might.
PS: It's useful to use a tool like Firebug to see if the application does in fact receive the response from the server (that would mean that, for example, you do need the setCallbackParam call) or maybe there's something wrong on the server side (for whatever reason).
You have to read the callback request-Parameter (default callback, value something like __gwt_jsonp__.P0.onSuccess) on serversite and have to modify the output to
<callback>(<json>);
In this case:
__gwt_jsonp__.P0.onSuccess(<json>);
Both of these guys are absolutely correct, but here is a concrete example to help you understand exactly what they are referring too.
This is a public JSON api. Take a look at the results:
http://ws.geonames.org/postalCodeLookupJSON?postalcode=M1&country=GB&maxRows=4
This public API supports JSONP through the predefined parameter 'callback'. Basically whatever value you pass into callback, will be used as the function name to wrap around the JSON data you desire. Take a look at the results of these few requests:
http://ws.geonames.org/postalCodeLookupJSON?postalcode=M1&country=GB&maxRows=4&callback=totallyMadeUp
http://ws.geonames.org/postalCodeLookupJSON?postalcode=M1&country=GB&maxRows=4&callback=trollingWithJSONP
It could be happening because of another reason, that the webservice call is returning a JSON object and but the callback is expecting JSONP object (note there is a difference).
So if you are dealing with google maps api, and you are seeing this exception, you need to change it to api provide by maps api, something like
final GeocoderRequest request = GeocoderRequest.create();
request.setAddress(query);
try {
GWT.log("sending GeoCoderRequest");
if (m_geocoder == null) {
m_geocoder = Geocoder.create();
}
m_geocoder.geocode(request, new Geocoder.Callback() {
#Override
public void handle(final JsArray<GeocoderResult> results,
final GeocoderStatus status) {
handleSuccess(results, status);
}
});
} catch (final Exception ex) {
GWT.log("GeoCoder", ex);
}
Or else you could use RequestBuilder as in gwt library.