Inconsistent ServiceStack exception handling - servicestack

I have a simple service built with ServiceStack
public class GetContactMasterDataService : IService<GetContactMasterData>
{
public object Execute(GetContactMasterData getContactMasterData)
{
return ContactApi.FetchContactMasterData();
}
}
In a different namespace:
public class GetContactMasterData
{
}
public class GetContactMasterDataResponse
{
public ResponseStatus ResponseStatus { get; set; }
}
public static GetContactMasterDataResponse FetchContactMasterData()
{
throw new ApplicationException("CRASH");
}
When I send a JSON request I correctly get:
{
"ResponseStatus":{
"ErrorCode":"ApplicationException",
"Message":"CRASH",
}
}
When I send a soap12 request with soapUI, I get the typical yellow screen of death
<html>
<head>
<title>CRASH</title>
...
<h2> <i>CRASH</i> </h2></span>
<b> Description: </b>An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
...
<b> Exception Details: </b>System.ApplicationException: CRASH<br><br>
Is this the expected behavior? How can I get a neatly serialized ResponseStatus similar to the JSON response.
Thanks in advance.

The HTML error page you get doesn't looks like it's coming from ServiceStack, check to see if your website has something that could be hijacking the errors with its own page, e.g: <customErrors />.
The correct behavior for SOAP endpoints is to throw a SOAP fault which if you're using either the Soap11ServiceClient or Soap12ServiceClient generic service clients will be converted to a WebServiceException as seen in this Integration test:
var client = new Soap12ServiceClient(ServiceClientBaseUri);
try
{
var response = client.Send<AlwaysThrowsResponse>(
new AlwaysThrows { Value = TestString });
Assert.Fail("Should throw HTTP errors");
}
catch (WebServiceException webEx)
{
var response = (AlwaysThrowsResponse) webEx.ResponseDto;
var expectedError = AlwaysThrowsService.GetErrorMessage(TestString);
Assert.That(response.ResponseStatus.ErrorCode,
Is.EqualTo(typeof(NotImplementedException).Name));
Assert.That(response.ResponseStatus.Message,
Is.EqualTo(expectedError));
}

Related

Spring Integration Java DSL and Http.outboundGateway: How to get the real error message JSON

How to get the real error message JSON when the Http.outboundGateway call is failed.
For example my program does the HTTP POST. The operation fails with the error code 400 Bad Request and the real error message is (tested with the Postman):
{
"name": [
"This field is needed."
]
}
I have the error channel like this:
#Bean
private IntegrationFlow myErrorChannel() {
return f -> f.handle("myErrorHandler", "handle")
....
;
}
and the Class MyErrorHandler is like this:
#Service
public class MyErrorHandler {
#ServiceActivator
public Message<MessageHandlingException> handle(Message<MessageHandlingException> message) {
...
}
}
Does the MessageHandlingException contain the real error message?
{
"name": [
"This field is needed."
]
}
I debugged the code and checked the MessageHandlingException exception and it seems it doesn't contain the real error message. The detailMessage contains the text 400 Bad Request, but I want to know the real error message.
How to get the real error message?
Edit:
This is working (I'm assigning the real error message to the new payload):
final RestClientResponseException clientException = (RestClientResponseException) messagingHandlingException.getCause();
payload = clientException.getResponseBodyAsString();
The Resttemplate uses a DefaultResponseErrorHandler by default. That one has a logic like:
protected void handleError(ClientHttpResponse response, HttpStatus statusCode) throws IOException {
String statusText = response.getStatusText();
HttpHeaders headers = response.getHeaders();
byte[] body = getResponseBody(response);
Charset charset = getCharset(response);
switch (statusCode.series()) {
case CLIENT_ERROR:
throw HttpClientErrorException.create(statusCode, statusText, headers, body, charset);
case SERVER_ERROR:
throw HttpServerErrorException.create(statusCode, statusText, headers, body, charset);
default:
throw new UnknownHttpStatusCodeException(statusCode.value(), statusText, headers, body, charset);
}
}
An exception from here is thrown to the HttpRequestExecutingMessageHandler which really wraps it into the MessageHandlingException.
Since you say that you can handle the last one via your MyErrorHandler, I would suggest you just take a look into the cause of the MessageHandlingException, and you'll that RestClientResponseException with all the required info from the response.

Webapi 2 global exception handling not raised

I'm uising web api 2 to develop services for a client, to manage errors we are using a ExceptionsFilterAttribute, but as you know, in this level not all exception are catched.
Some errors are raised in protected void Application_AuthenticateRequest(Object sender, EventArgs e) and I want to handle them and send a custom message to our client to give him more details about the error, to solve this I create a GlobalExceptionHandler
public class GlobalExceptionHandler: ExceptionHandler
{
//A basic DTO to return back to the caller with data about the error
private class ErrorInformation
{
public string Message { get; set; }
public DateTime ErrorDate { get; set; }
}
public override void Handle(ExceptionHandlerContext context)
{
//Return a DTO representing what happened
context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.InternalServerError,
new ErrorInformation { Message="We apologize but an unexpected error occured. Please try again later.", ErrorDate=DateTime.UtcNow }));
//This is commented out, but could also serve the purpose if you wanted to only return some text directly, rather than JSON that the front end will bind to.
//context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.InternalServerError, "We apologize but an unexpected error occured. Please try again later."));
}
}
In WebApiConfig i added this line :
config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
The the Application_AuthenticateRequest raise some errors but GlobalExceptionHandler is never reached.
Do you have any idea how can I solve this issue ?
Thanks in advance.
Application_AuthenticateRequest does not come in the Web API pipeline. So if an exception is thrown in this method those can be caught by the Web API exception handler, because the exception is thrown before the Web API pipeline is started.
There are two ways to do this:
Either change the authentication mechanism and use Web API Authentication(IAuthenticationFilter) instead of Application_AuthenticateRequest.
If this project has only Web API related controllers, not like MVC and all.
Or use Application_Error in the Global.asax.cs file to catch the exception thrown in Application_AuthenticateRequest

Impossible to show Custom Error page with Nancy on OWIN

I have a website using Nancy which is hosted using OWIN.
In my Startup.cs file I define the PassThroughOptions as follows:
public void Configuration(IAppBuilder app)
{
app.UseNancy(o => {
o.PassThroughWhenStatusCodesAre(
HttpStatusCode.NotFound,
HttpStatusCode.InternalServerError
);
o.Bootstrapper = new Bootstrapper();
});
app.UseStageMarker(PipelineStage.MapHandler);
}
I need to pass-through the NotFound requests, so that things like my bundled .less files or miniprofiler-results or static files in the root of my site (robots.txt or sitemap.xml) work.
I also have a custom StatusCodeHandler for the 404 code, which also checks a custom header to distinguish between static files (or .less bundles/miniprofiler) and actual stuff that is not found in my modules' methods.
public void Handle(HttpStatusCode statusCode, NancyContext context)
{
Log.Warn("Not found: " + context.Request.Url);
base.Handle(statusCode, context, "Errors/NotFound");
}
This handler then should actually show the error page.
protected void Handle(HttpStatusCode statusCode, NancyContext context, string view)
{
var response = new Negotiator(context)
.WithModel(GetErrorModel(context))
.WithStatusCode(statusCode)
.WithView(view);
context.Response = responseNegotiator.NegotiateResponse(response, context);
}
But the error page is never shown. The request is processed three times and eventually the default IIS error page is shown (using errorMode="Custom" for httpErrors) or simply a white page (using existingResponse="PassThrough" for httpErrors).
Is there any way to display something so simple as a custom error page when hosting a Nancy website on OWIN?
What you've got there looks good, it looks like you've be using the Hosting Nancy with Owin docs.
Here's what works for me:
The Startup.cs (required for Owin): (We've both coded the configuration function differently, you're just using the extension helper while I'm not. Same result. This is in my App.Web project.)
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseNancy(options =>
{
options.Bootstrapper = new BootStrapper();
options.PerformPassThrough = context => context.Response.StatusCode == HttpStatusCode.NotFound;
});
app.UseStageMarker(PipelineStage.MapHandler);
}
}
404 handler: (As per the docs, doesn't matter where this is in the project, by implementing IStatusCodeHandler it'll be automatically picked up by Nancy This is in my App.WebApi project with other module classes.)
public class StatusCode404Handler : IStatusCodeHandler
{
public bool HandlesStatusCode(HttpStatusCode statusCode, NancyContext context)
{
return statusCode == HttpStatusCode.NotFound;
}
public void Handle(HttpStatusCode statusCode, NancyContext context)
{
var response = new GenericFileResponse("statuspages/404.html", "text/html")
{
StatusCode = statusCode
};
context.Response = response;
}
}
The 'statuspages' folder in my App.Web project:
Check this SO post for a comparison of using GenericFileReponse or ViewRenderer (How to display my 404 page in Nancy?).

Spring integration, Setting error-handler on http outbound gateway

If I add a custom error-handler to an int-http:outbound-gateway, the response body is not unmarshalled according to the expected-response-type, instead I only get a ResponseEntity returned. My custom error handler is pretty simple:
public class MyResponseErrorHandler extends DefaultResponseErrorHandler {
private static final Logger log = LoggerFactory.getLogger(AlmaGetUserResponseErrorHandler.class);
#Override
public boolean hasError(final ClientHttpResponse response) throws IOException {
// stop http 400 from returning true to error here.
log.debug("Request has returned error code {}", response.getStatusCode());
if (response.getBody() != null) {
String returnBody = IOUtils.toString(response.getBody(), "UTF-8");
log.debug("Checking error from response, code {}, body {}", response.getStatusCode(), returnBody);
}
return false;
}
}
As soon as I remove the error-handler, it unmarshalls the XML response into my POJO correctly.
The issue above was that the MyResponseErrorHandler class was streaming out the body content before it was being passed to the marshaller for expected-response-type. Hence the body was null and a plain ResponseEntity was returned.

I get a 500 page instead of a ResponseStatus from exceptions within ServiceStack Service

Using ServiceStack 4.0.33 and given the following simplified DTOs...
[Route("/products")]
[Route("/products/{Id}")]
public class Product : IReturn<ProductResponse>
{
[PrimaryKey]
public string Id { get; set; }
public string Description { get; set; }
}
public class ProductResponse
{
public Product Product { get; set; }
}
with the following simplified service...
public class ProductService : Service
{
public object Post(Product product)
{
Db.Insert<Product>(product);
return new ProductResponse() { Product = product };
}
}
and calling it via this in my ProductsController
using (var productService = ResolveService<ProductService>())
{
var result = productService.Post(product);
if (result.IsErrorResponse())
return View(product);
else
return RedirectToAction("Index");
}
If I try to post a new Product with an intentional duplicate primary key, I get a 500 error HTML-style page instead of the ResponseStatus getting populated and returned...
I've seen lots of different StackOverflow posts about different reasons that ResponseStatus won't get populated, but I've tried several things to no avail. Am I missing something (hopefully simple)?
Where do you define the behavior that a duplicate key would be handled differently than HTTP 500. What other response would you expect? ResponseStatus can contain HTTP 500 which merely indicates a server-side error.
You have to specifically define that you want to handle the error differently and if so what type of error you want (which error code, which message) as explained here.
For instance:
public object Get(User request)
{
throw HttpError.NotFound("User {0} does not exist".Fmt(request.Name));
}
Check out the ServiceStack tutorial for more.
The error page you're getting is a custom ASP.NET Error page which hijacks any custom 500 HTTP error responses returned by your ASP.NET web application.
It can be disabled with:
<system.web>
...
<customErrors mode="Off" />
</system.web>
<system.webServer>
<httpErrors errorMode="Detailed" />
</system.webServer>
Here's another alternative of disabling IIS errors by setting TrySkipIisCustomErrors = true which in ServiceStack can be set with:
GlobalRequestFilters.Add((req, res, dto) =>
{
((HttpResponse)res.OriginalResponse).TrySkipIisCustomErrors = true;
});

Resources