seeing multiple log entries for one error - c#

I have a web api controller which is calling a service (using Mediatr) to get back some data, I tried to force an error to get exception logging to work. But I'm noticing that for 1 error I see 3 entries in the logs, I would assume 1 error = 1 entry, the RequestId is the same for all 3 entries.
In Program.cs after the builder.Build() I have:
app.UseExceptionHandler("/error");
My ErrorsController:
[Route("/error")]
public IActionResult HandleError([FromServices] IHostEnvironment hostEnvironment)
{
if (!hostEnvironment.IsDevelopment())
{
// if we hit this outside development return 404
return NotFound();
}
var exception = HttpContext.Features.Get<IExceptionHandlerFeature>().Error!;
return Problem(
detail: exception.StackTrace,
title: exception.Message
);
}
I'm throwing a test error in the service class with:
throw new Exception("something wrong");
Now when I hit that method in the log (db and console) I see 3 entries:
HTTP "GET" "/api/query/staff" responded 500 in 593.6407 ms -> Has StackTrace
An unhandled exception has occurred while executing the request. -> Has same StackTrace as above
HTTP "GET" "/error" responded 500 in 43.4958 ms -> No StackTrace
they all have the same RequestId.
I was trying to log just once, so it's easier to find the exception in the logs, rather than see it 3 times, which i'm assuming is from the service->controller (which called service)->error controller.

Related

IEnumerable that throws exception returns invalid Json when passed into OkResult in ASP.NET Core Web API

Start up a new ASP.NET Core Web API project in Visual Studio.
Now change the ValuesController.Get() action to be this:
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
var results = new[] {"hi"}.Select<string, string>(x => throw new ArgumentException());
return Ok(results);
}
When you hit this you get a 200 response with a response body of just [
Now if you now change it to enumerate the erroring Select before passing to Ok() it will raise an error correctly and return 500 with details of the error as expected in the default ASP.NET API template:
var results = new[] {"hi"}.Select<string, string>(x => throw new ArgumentException());
results.ToList();
return Ok(results);
What is happening here?
In the first example, the status code and response headers are sent to the client before the JSON serialisation starts. Giving the JSON serialiser an IEnumerable<string> results in deferred creation of the collection, which ends up being performed during the serialisation process. This means that the 200 status code and response headers are sent before the exception is thrown. Because the status code has already been sent, it cannot be changed from 200. The response cannot be "undone" either - it's a forward-only stream of data.
In the second example, the collection is created before the JSON serialisation process runs. In this case, the exception is thrown before the call to return Ok(results) can be reached. Whatever you're using for global exception handling catches this exception and writes out a response with a status code of 500.

How to make a "webhook"?

I need the "WinForm" application for correspondence in viber.
 "Webhook" is planned to receive data (events) from viber, then the data will be used in the application "WinForm".
I did:
created the project "ASP.NET Web Application (.NET Framework)";
chose a template - "Empty" + "MVC" + "API";
added controller "Controller MVC 5 - empty". Controller name "HookController";
I run the application "Postman";
"Postman". I set the request "POST";
"Postman". I set the link http://localhost:44836/Hook;
"Postman". Click "SEND";
The result, see the picture "- = RESULT = -";
If I understand the theory correctly, then after performing the "Postman" action. I click "SEND", the ViberProcess (HttpContext context) method should be executed in the HookController.cs controller and the code should stop at the breakpoint.
This is not happening.
Documentation Viber REST API - link
Question.
How to make a Webhook?
Code HookController.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
//
using System.Runtime.Remoting.Contexts;
namespace WebAppl1.Controllers
{
public class HookController : Controller
{
// GET: Hook
//public ActionResult Index()
//{
// return View();
//}
[HttpPost]
// [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public void ViberProcess(HttpContext context)
{
try
{
Stream s = context.Request.InputStream;
// Stream s = Context.Request.InputStream;
// or Stream s = HttpContext.Current.Request.InputStream;
s.Position = 0;
StreamReader reader = new StreamReader(s);
string jsonText = reader.ReadToEnd();
// Other code that converts json text to classes
}
catch (Exception e)
{
// .....
}
}
}
}
7. "Postman". Click "SEND";
8. The result, see the picture "- = RESULT = -";
Server error in application '/'.
Could not find this resource.
Description: HTTP 404. The resource (or one of its dependencies) may have been deleted, received a different name, or may be temporarily unavailable. Review the following URL and verify that it is correct.
Requested URL: / Hook
Version Information: Microsoft .NET Framework Version 4.0.30319; ASP.NET version: 4.7.3062.0
Update_1
I use the link http://localhost:44836/api/Hook
The code does not stop at breakpoint.
Result:
{
"Message": "Could not find the HTTP resource corresponding to the request URI \" http://localhost:44836/api/Hook\ ".",
"MessageDetail": "Could not find the type corresponding to the controller \" Hook \ " . "
}
I use the link http://localhost:44836/Hook/ViberProcess
The code does not stop at breakpoint.
Result
Server error in application '/'.
For this object, no parameterless constructors are defined.
Description: An unhandled exception occurred during the execution of the current web request.
Examine the stack trace for more information about this error and the code snippet that caused it.
Exception Details: System.MissingMethodException: No parameter-less constructors are defined for this object.
Source Error:
An unhandled exception occurred during the execution of the current web request.
Information on the origin and location of the exception can be obtained using the following exception stack trace.
Just remove the HttpContext context in your ViberProcess action.
So, the method will become
public IActionResult ViberProcess()
{
Stream s = HttpContext.Current.Request.InputStream;
//... continue your code from here.
}
The reason behind this is, You have mention HttpContext context as an Argument of ViberProcess but while you are sending request it will search with the Exact schema.
So, in your request, you can not pass the HttpContext from anywhere. So, this request will never be found.
Here is the screenshot:
Try this an let me know if you still have an issue.

Elmah Raise() records inner exception

I'm trying to raise an exception using Elmah like this:
try
{
Foo();
}
catch (WebException ex)
{
var nex = new Exception("Foo failed", ex);
Elmah.ErrorSignal.FromCurrentContext().Raise(nex);
}
However, what Elmah records is the inner exception ex, not my new wrapper exception nex, i.e. the resulting database record has:
Type = "System.Net.WebException", Message = "The remote server returned an error: (400) Bad Request."
rather than, as I would expect:
Type = "System.Exception", Message = "Foo failed"
What on earth's going on?
ELMAH shows the type of the inner exception on the list of exceptions (/elmah.axd). If you click the Details link next to the error message, I'm pretty sure you'll see something like this:
System.Exception: Foo failed ---> System.Net.WebException
I just created a test project and verified that this is the experienced behaviour.
Edit: As discussed in comments, use of the base exception in the Type and Message fields appears to be the intended behavior.

How to catch "A potentially dangerous Request.Path value was detected from the client (:)" to avoid web role crash?

My MVC 5 web application running on Azure Cloud Service crashed with an unhandled exception "A potentially dangerous Request.Path value was detected from the client (:)".
The cause for this crash was some third party (maybe malicious) hit my endpoints with url:
http://myExampleHost.com/m:443/templates
The colon in the url cannot pass the path validation.
Some answers (A potentially dangerous Request.Path value was detected from the client (*)) suggest change the validate rules. However, out of security concerns, we may not want to compromise on this.
The ideal behavior for it that: we catch the exception, log it and return some error messages without crashing. How should we do that?
A more general question on this would be: how to catch an exception before the request hits controllers in MVC?
The ideal behavior for it that: we catch the exception, log it and return some error messages without crashing. How should we do that?
Per my understanding, you could leverage the Application_Error event to capture unhandled exception(s) within ASP.NET. Here is my test, you could refer to it:
protected void Application_Error()
{
HttpContext httpContext = HttpContext.Current;
var exception=Server.GetLastError();
var httpException = exception as HttpException ?? new HttpException(500, "Internal Server Error", exception);
var jsonResponse = new
{
Message = exception.Message,
StatusCode = httpException.GetHttpCode(),
StackTrace=httpException.StackTrace
};
httpContext.Response.ContentType = "application/json";
httpContext.Response.ContentEncoding = Encoding.UTF8;
httpContext.Response.Write(JsonConvert.SerializeObject(jsonResponse));
httpContext.Response.End();
}
Note: You could also redirect to a specific error page.
Moreover, you could leverage the customErrors in web.config and catch the error page for the specific HTTP error code. Also, you could check the HTTP status code under the Application_EndRequest event and write your custom response, details you could refer to this similar issue. Additionally, I would recommend you follow Demystifying ASP.NET MVC 5 Error Pages and Error Logging for more details about error handling.

Why changing the status code after writing to the body returns 504?

In ASP.NET 5 I've seem that the following code gives an error 504 in the response:
public class Startup
{
public void Configure(IApplicationBuilder app)
{
app.Use((next) => {
return async (context) => {
context.Response.StatusCode = 200;
await context.Response.WriteAsync("Hello World");
context.Response.StatusCode = 201;
await context.Response.WriteAsync("Status code changed");
};
});
}
}
I know we shouldn't change the status code in this arbitrary manner, but my question here is: why changing it gives a problem? The fact is that, commenting the line that changes the status code, and using Response.WriteAsync twice, doesn't give any kind of problem, but changing the status code gives.
When we do it this returns a 504 status code. I believe it has to do with the way the response is sent to the client. It happens because when we call Respose.WriteAsync the response message starts being sent already? What's the reason for this error to occur?
Headers are sent the moment content is written to the response body stream and so you cannot change the headers again...so if you are setting the status code again, then probably an exception is being thrown in the middleware to indicate this...
BTW this exception would cause the 504 that you are seeing(like currently there is no response buffering layer which could catch these kind of exceptions and returns a 500 Internal Server with an error message)...you can put a try-catch block to capture the exception message and see what it says..

Categories