I would like to get automatic exception serialization without manually adding ResponseStatus to the response DTO.
Based on this info on unhandled exception behavior I wrote the following code
public class ContactService : RestServiceBase<Contact>
{
public override object OnGet(Contact request)
{
return ContactApi.GetContactInfo(request);
}
//To trigger the serialization of the Exception to ResponseStatus
protected override object HandleException(Contact request, Exception ex)
{
throw ex;
}
<snip />
}
Do you see any issues with using the library in this manner?
Thanks in advance.
UPDATE: I would like to get the following response when there is an exception without having to add ResponseStatus property to my response DTO object.
I am able to achieve this with by overriding the HandleException method as shown above.
My question is:
Can overriding the default exception handling behavior in this manner cause any problems down the road?
{
"ResponseStatus":{
"ErrorCode":"ApplicationException",
"Message":"CRASH",
}
}
Related
Could you please give me an advice, what is the proper way to return HttpStatus.BAD_REQUEST from webflux handler?
Here's the code, it seems to work properly, exception message returns as needed, but the response status is 200, while needed to be 400. Please note, that returning media type is TEXT_EVENT_STREAM -
#Component
public class ResolveHandler {
public Mono<ServerResponse> resolve(ServerRequest request) {
return ServerResponse.ok().contentType(MediaType.TEXT_EVENT_STREAM)
.body(
new ResultsFluxer(
Integer.valueOf(request.queryParam("numberOfIterations").orElse("0")),
request.queryParam("function1").orElse(""),
request.queryParam("function2").orElse(""),
orderingType
)
.getResult()
.onErrorResume(e -> Flux.just(e.getMessage()))
, Flux.class);
}
}
Server Side
public class MyServices : Service
{
public object Get(Hello request)
{
throw new InvalidOperationException("test error message");
//return new HelloResponse { Result = "Hello, {0}!".Fmt(request.Name) };
}
}
Client Side
try
{
var client = new JsonServiceClient("http://localhost:28586/");
var response = client.Get<HelloResponse>(new Hello { Name = "DHJ" });
}
catch (WebServiceException ex)
{
// ex.ErrorCode = "InvalidOperationException" // No Problem.
// ex.ErrorMessage = null // always null. Why?
}
And i saw the docs of ServiceStack like below:
Throwing C# Exceptions
In most cases you won’t need to be concerned with ServiceStack’s error handling since it provides native support for the normal use-case of throwing C# Exceptions, e.g.:
public object Post(User request)
{
if (string.IsNullOrEmpty(request.Name))
throw new ArgumentNullException("Name");
}
Default Mapping of C# Exceptions to HTTP Errors
By Default C# Exceptions:
Inheriting from ArgumentException are returned with a HTTP StatusCode of 400 BadRequest
NotImplementedException or NotSupportedException is returned as a 405 MethodNotAllowed
AuthenticationException is returned as 401 Unauthorized
UnauthorizedAccessException is returned as 403 Forbidden
OptimisticConcurrencyException is returned as 409 Conflict
Other normal C# Exceptions are returned as 500 InternalServerError
This list can be extended with user-defined mappings on Config.MapExceptionToStatusCode.
Your HelloResponse class needs a ResponseStatus property, from the Error Handling docs:
Error Response Types
The Error Response that gets returned when an Exception is thrown varies on whether a conventionally-named {RequestDto}Response DTO exists or not.
If it exists:
The {RequestDto}Response is returned, regardless of the service method's response type. If the {RequestDto}Response DTO has a ResponseStatus property, it is populated otherwise no ResponseStatus will be returned. (If you have decorated the {ResponseDto}Response class and properties with [DataContract]/[DataMember] attributes, then ResponseStatus also needs to be decorated, to get populated).
Otherwise, if it doesn't:
A generic ErrorResponse gets returned with a populated ResponseStatus property.
I'm trying to manage exceptions in a Spring MVC context and send different http statuses in response.
I tried this :
#ResponseStatus(value = HttpStatus.SERVICE_UNAVAILABLE)
public class UnavailableServiceException extends RuntimeException {
}
When I send this exception in my controller, it works fine : response http status is 503.
But I want my controller to send json, and with this configuration, when 503 is send, response is html :-/
So I tried this :
Removing #ResponseStatus on my exception class and defining an Exception handler.
#ExceptionHandler(UnavailableServiceException.class)
public ResponseEntity<ExceptionJSONInfo> handleUnavailableService(UnavailableServiceException exception) {
return new ResponseEntity<ExceptionJSONInfo>(new ExceptionJSONInfo("Error xxx", exception.getMessage()), HttpStatus.SERVICE_UNAVAILABLE);
}
It's ok : 503 and json.
But I want to manage 5 or 6 different exceptions : how can I do this without duplicating handlers ?
Is it possible to retrieve #ResponseStatus defined on an exception ?
If not, my next idea will be to define an httpStatus attribute in a super class, mother of all my exceptions. And then :
public class UnavailableServiceException extends MySuperException {
super(HttpStatus.SERVICE_UNAVAILABLE);
}
#ExceptionHandler(MySuperException.class)
public ResponseEntity<ExceptionJSONInfo> handleUnavailableService(MySuperException exception) {
return new ResponseEntity<ExceptionJSONInfo>(new ExceptionJSONInfo("Error xxx", exception.getMessage()), exception.getHttpStatus());
}
Any better idea ?
Thanks
Manu
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
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.