Different error response body when on Azure - json

I have an action which returns an error with JSON:
public JsonResult Error()
{
this.Response.StatusCode = (int)HttpStatusCode.BadRequest;
return this.Json(new { error = "some error" }, JsonRequestBehavior.AllowGet);
}
When I test this locally, the body of the response is:
{"error":"some error"}
as expected but when published to Azure, the response body is
Bad Request
Why would there be a different behavior and how can I make Azure respond with the JSON?

Try telling IIS to not use it's error pages by using Response.TrySkipIisCustomErrors.
Resulting code would look like:
public JsonResult Error()
{
this.Response.StatusCode = (int)HttpStatusCode.BadRequest;
this.Response.TrySkipIisCustomErrors = true;
return this.Json(new { error = "some error" }, JsonRequestBehavior.AllowGet);
}

Simply put
<system.webServer>
<httpErrors existingResponse="PassThrough" />
</system.webServer>
in the web.config file.
I found the solution through this blog post.

Related

Minimal API - Invalid JSONs in request body

I'm facing a behavior in Minimal API that I can't understand.Consider the following simple Minimal API:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseExceptionHandler((exceptionApp) =>
{
exceptionApp.Run(async context =>
{
context.Response.ContentType = MediaTypeNames.Text.Plain;
var feature = context.Features.Get<IExceptionHandlerPathFeature>();
if (feature?.Error is BadHttpRequestException ex)
{
context.Response.StatusCode = 400;
var message =
(ex.InnerException is JsonException)
? "The request body is an invalid JSON"
: "Bad Request";
await context.Response.WriteAsync(message);
}
else
{
context.Response.StatusCode = 500;
await context.Response.WriteAsync("There is a problem occured");
}
});
});
app.MapPost("/models", (Model model) => Results.Created(string.Empty, model));
app.Run();
public record Model(int Value, string Title);
When I run the application in the Development environment, and pass an invalid JSON like
{
"value": 1,
"Title": Model #1
}
the custom exception handler is called and I have to control the behavior of the API. But whenever
I run the application in the Production environment, the framework automatically returns a
"bad request" response without letting me control the response.
Could anyone explain this behavior to me? I really need my exception handler to handle invalid input
JSON exceptions.
Thanks
After digging into ASP.Net Core source code for a while, I found that the following line resolves the issue.
builder.Services.Configure<RouteHandlerOptions>(o => o.ThrowOnBadRequest = true);

Why HttpClient.GetFromJsonAsync doesn't throw an exception when the response is HTML instead of JSON?

I'm learning Blazor.
I have created a Blazor WASM App with the "ASP.NET Core Hosted" option.
So I have 3 projects in the solution: Client, Server and Shared.
The following code is in the Client project and works perfectly when the endpoint is correct (obviously). But at some point I made a mistake and messed up the request URI, and then I noticed that the API returned an HTML page with code 200 OK (as you can see in the Postman screenshot below the code).
I expected one of my try-catches to get this, but the debugger jumps to the last line (return null) without throwing an exception.
My first question is why?
My second question is how can I catch this?
I know fixing the endpoint fixes everything, but would be nice to have a catch that alerts me when I have mistyped an URI.
Thanks.
private readonly HttpClient _httpClient;
public async Task<List<Collaborator>> GetCollaborators()
{
string requestUri = "api/non-existent-endpoint";
try
{
var response = await _httpClient.GetFromJsonAsync<CollaboratorsResponse>(requestUri);
if (response == null)
{
// It never enters here. Jumps to the last line of code.
}
return response.Collaborators;
}
catch (HttpRequestException)
{
Console.WriteLine("An error occurred.");
}
catch (NotSupportedException)
{
Console.WriteLine("The content type is not supported.");
}
catch (JsonException)
{
Console.WriteLine("Invalid JSON.");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return null;
}
it is a never good idea to use GetFromJsonAsync, You are not the first who are asking about the strange behavior. Try to use GetAsync. at least you will now what is going on.
var response = await client.GetAsync(requestUri);
if (response.IsSuccessStatusCode)
{
var stringData = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<CollaboratorsResponse>(stringData);
... your code
}
else
{
var statusCode = response.StatusCode.ToString(); // HERE is your error status code, when you have an error
}

Angular 6 error handlig - HttpErrorResponse has undefined status

I have a Angular 6 client consuming a REST Api developed with .Net Web Api.
Everything is working except for the error handling. When I try to process the error to react differently to different status codes (404, 403, 409, 500...) I simply can't make it work. The HttpErrorResponse object doesn't have any of the fields it is supposed to (like 'status' or 'error').
I've made a super simple service that reproduces the issue:
Request on the service.ts
public test(): Observable<any> {
let url = this.templatesUrl + '/myMethod';
console.log('GET myMethod ' + url);
return this.http.get<any>(url)
.pipe(catchError(this.handleError));
}
Error handler (pretty much straight from the official documentation):
private handleError(error: HttpErrorResponse) {
console.warn(error);
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.message}`);
}
// return an observable with a user-facing error message
return throwError('Unexpected error');
}
Service on the .Net side:
[HttpGet]
[Route("myMethod")]
public IHttpActionResult myDotNetMethod()
{
return InternalServerError(new Exception("Details about the issue"));
}
The service is called and it returns a status code 500 along with a json object:
The status of the response:
The response header, it is json:
The json object:
And what the log shows: no status and pretty much an empty object:
Loosk like the HttpErrorResponse is pretty much empty. But the response from the API was fine, the status code is there and the json object too.
What am I missing?
Update: In case you are wonder what hides behind that "Internal Server Error" that shows in the log (it is just the callstack generated by chrome):
Update 2: Here's the error object under the microscope. It is simply "Internal Server Error". No trace of status or message.
Solved... the object was empty due to an interceptor. So if something similar is happening to you check those out.
I'm sorry to have wasted everyone's time, I was unaware of the existance of that particular interceptor.
I think your problem is how you are throwing the error in .Net.
Try this:
var statusCode = HttpStatusCode.InternalServerError;
var response = new HttpResponseMessage(statusCode)
{
Content = new ObjectContent<object>(
new
{
Message = "Error Message",
ExceptionMessage = "StackTrace"
},
new JsonMediaTypeFormatter())
};
throw new HttpResponseException(response);
Or if it does not work try this: https://stackoverflow.com/a/28589333/8758483
Another good idea is to centralize your error handling by implementing an ErrorHandler in Angular.
import { ErrorHandler } from '#angular/core';
#Injectable()
export class GlobalErrorHandler implements ErrorHandler {
handleError(error) {
// your custom error handling logic
}
}
Then you tell Angular you want to use this class instead of the default one by providing it in you NgModule:
#NgModule({
providers: [{provide: ErrorHandler, useClass: GlobalErrorHandler}]
})
If you want more detail you can read this article:
Expecting the Unexpected — Best practices for Error handling in Angular
In the response the property is called "Message" and not "message".

AWS API Gateway Header and Body Mappings in Integration Response

I am trying to properly setup Body Mapping and Header Mapping in the Integration Response for an API Gateway endpoint.
In our Lambda we have
if (response.statusCode == 200) {
context.succeed(output);
} else if (response.statusCode == 206) {
var paginationObject = {
errorType : "PartialContent",
errorCode : 206,
detailedMessage : "PartialContent Returned",
stackTrace : [],
data : {
output
}
};
context.fail(JSON.stringify(paginationObject));
}
I then handle fetching this in the Integration Response using a Lambda Error Regex of .*PartialContent.* and have my Body Mapping Template as
#set($allParams = $input.params())
#set($body = $util.parseJson($input.json('$.errorMessage')))
$body
This gives me the correct HTTP status code and JSON output, but it has too much data in the body. The response looks like:
{
"errorType":"PartialContent",
"errorCode":206,
"detailedMessage":"PartialContent Returned",
"stackTrace":[],
"data":{
"output":{
"status":206,
"bodyJson":[{"call_date":"2017-08-19 18:17:21"}],
"headers":{"date":"Thu, 02 Nov 2017 18:36:52 GMT",
"server":"Apache",
"x-pagination-page-size":10}
}
}
}
I want the headers to actually appear as headers in the response, and I want the body to just be the content inside of bodyJson
I've tried to change the body mapping template to use $body.data.output.bodyJson, but when I do that the body is completely empty. I've also got the headers set in the Header Mappers, trying both integration.response.body.headers.x-pagination-page-size and integration.response.header.x-pagination-page-size but both times the header is blank, even though I can see the proper values in the JSON output.
How do I get just the bodyJson element to be output as the body of the response? And how do I properly get the headers mapped?
Did you try to use Lambda Error Regex in Integration Response?
For example:
.*"status":400.*
body mapping templetes:
#set ($errorMessageObj = $util.parseJson($input.path('$.errorMessage')))
{
"status" : "$errorMessageObj.status",
"errorType" : "$errorMessageObj.errorType",
"message" : "$errorMessageObj.errorMessage"
}
I created an error function in my Lamda:
function error(status, errorType, errorMessage, callback){
callback(JSON.stringify({
status: status,
errorType: errorType,
errorMessage: errorMessage
}));
}
usage:
error(404, "Not Found", "Resource is not found", callback);

Configuration IIS 7 for JSON

i have this code for receiving data from server:
try
{
var data = _model.GetAll().ToList();
if (data.Count > 100)
return SendMessage($"Too much results", HttpStatusCode.Forbidden);
var result = JsonConvert.SerializeObject(data,
new JsonSerializerSettings { Converters = new JsonConverter[] { new StringEnumConverter() } });
return SendMessage(new{ results = result });
}catch (Exception ex)
{
return SendMessage("Server error.", HttpStatusCode.InternalServerError);
}
SendMessage method:
protected JsonResult SendMessage(string message, object data, HttpStatusCode code = HttpStatusCode.OK)
{
Response.StatusCode = (int)code;
return Json(new { message, data }, JsonRequestBehavior.AllowGet);
}
When method return 403 http code, i localhost is everything ok. Method send data in content-type application/json. But when I deploy my code to web server (IIS 7) method send content-type text/html and data is empty.
Where is problem? How i must configure IIS server?
Thanks for advices
Here is solution for my problem: https://forums.iis.net/t/1213176.aspx.
Open your IIS > click web site > Error Pages > here under "Alerts" section click on "Edit Features Settings..." it will show following three option :
1] Custom error pages
2] Detail errors
3] Detailed errors for local requests and custom error pages for remote requestes.
select 2nd option Detail errors click Ok.