I'm a beginner in ASP.NET Core, just a question on how middleware generate error.
I'm reading a book that explain the importance of order when you configure middleware:
But I'm a little bit confused, for the second scenario, why can't the image resizing middleware produce an error like:
Because it will be logical for a middleware to generate an error before calling next():
public class ImageResizeMiddleware
{
private readonly RequestDelegate _next;
public ImageResizeMiddleware (RequestDelegate next) { _next = next }
public Task Invoke(HttpContext context)
{
... // if an error occurs here, then 500 should be added to the context here
await next(context); // control passed to the error handling middleware
}
}
So if an error occurs before next(context), then the error handling middleware can see 500 in HttpContext, no?
It depends! Does it make sense for an error to be propagated further in to the pipeline and possibly overwritten by another middleware/controller?
For an image resizing middleware I would expect the handler to check whether the request should be handled by and if not only then pass the request on to the next handler. If the request matches and is handled by the middleware it doesn't make sense to propagate the request further in to the pipeline to potentially be overwritten by something else and should instead return immediately once the response is written. This would mean that the error handling middleware would never be invoked and would not get a chance to prettify/log the error.
Imagine if authentication/authorisation middleware didn't short-circuit the pipeline and return immediately! You could end up with unauthenticated/unauthorised requests to potentially access resources they shouldn't have access to.
Simply put, if an error occurs then the middleware should return and not propagate the request further in to the pipeline.
The idea behind middleware is similar to how Unix commands are supposed to do one thing and do [that] well. By removing the need for each middleware to produce proper error responses, you are removing the need to duplicate the logic all over the place.
If you just look at the default error handling middleware, there are multiple ways to configure it: You could simply return a failure status code, you could have some handler that write directly to the response, you could also have a Razor view that is being displayed to show the user a nice error message.
If each middleware would now be responsible to generate this response, then each middleware would have to be able to do that. But middleware is usually designed to be rather independent: An authentication middleware does not need to care whether you even have Razor views in your application, and especially not how it could render an authentication failure using Razor. Instead, middlewares can rely on standard control mechanisms (e.g. exceptions) and just assume that someone else will hopefully take care of it.
And if you have the error handling middleware early in your pipeline, then that middleware can take care of it. And you only need to configure once how an error should be handled. And if a fancy Razor view should be rendered and returned to the user, then this can be done in this one place.
Related
Currently, our ASP.NET Core 3.1 web api's error handling sends everything to our error controller using app.UseExceptionHandling('/error'). This controller logs the error and sends the error response our clients expect. Unfortunately, our logs contain each error twice because Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware logs the error before our error controller. How can we completely remove/replace Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware such that we (a) log the error only once and (b) completely replaces the response with our content?
We decided to use app.UseExceptionHandling('/error') over app.Use<CustomMiddlewareErrorHandler>() because changing the content in middleware always produced the "response already started" error that we never see when we use the error controller. I've found tutorials that advice testing whether the response has already started, but we always want to replace it. I suppose we need to flush the response or something like that.
Can someone point me to a practical example that (a) prevents double logging and (b) allows me to completely replace the response after an error?
I have one application that sends a GET request to another application.
This request is generated once, and sent once. I have validated this by generating a System.Net.HttpWebRequest object, populating it, and debugging my workflow until I call request.GetResponse(). This is only called once.
In the application that recieves the request, I have overriden the AuthenticationHandler's HandleAuthenticateAsync method with some custom authentication logic. When I debug the request, my validation works, and I return a valid AuthenticateResult. However, immediately after this returned, my app goes into the HandleAuthenticateAsync a second time. This time the request is missing the Authentication header, and the app therefore returns a 401 response.
Does anyone have any clue what might be wrong here?
Found it. The answer for me was to remove app.UseHttpsRedirection(); from Startup.cs' Configure method, since I was calling this application through http://localhost for testing purposes.
As I understand Owin now it is a pipeline of modules you can define that handles incoming requests. Any module can return a response or pass the request to the next module. So that makes it very easy to add logging or authentication or whatnot, very cool.
But what if I would like to log responses? Can you create a module that runs for every response, irrespective of where the response came from in the pipeline? If it is possible, can you provide an example or link, I can't seem to find this scenario on the web.
Turn out it is quite simple and logical, This blogpost shows an example on how to time the request. Since a module either passes the request on to the next module or RETURNS a response it is just a question of registering a module as the first and processing the returnvalue with ContinueWith:
public Task Invoke(IDictionary<string, object> environment)
{
return _next(environment).ContinueWith(result =>
{
Logger.LogResult(result);
return result;
});
}
In the old days:
We used Response.Redirect, which sets the 302 response header and raises a ThreadAbortException to prevent anything else from happening after the redirect.
Now, with MVC:
We return a RedirectResult, which avoids the performance issues with ThreadAbortException and also allows the rest of the pipeline to inspect the results before actually sending them back to the browser. It's a different way of thinking about a redirect-- now instead of halting execution, a redirect is more like returning from a function.
My question has to do with mixing and matching these patterns.
Here's the requirement. We have an MVC site, and site contains an HttpModule that is in charge of authentication. If anything goes wrong with authentication, it drops cookies and redirects to an external web page. So the HttpModule makes a decision whether to send the redirect header or pass control to the MVC site. If it sends the redirect header, it has to halt execution-- if authentication failed, we don't want the site to be accessible in any way, shape, or form.
What's the "right" way to do this? Should the HttpModule simply use Response.Redirect just like we have always done? Or is there some clever way to accomplish this that is more consistent with the MVC pattern? Is there any way for the HttpModule to tell the pipeline to stop processing?
Or should I be using some completely different pattern, something that doesn't use an HttpModule? Perhaps an MVC filter? The thing is, the modularity/separation of concerns between the module and the site itself is very important. Anyone have any recommendations?
Thought I'd throw the answer up here in case anyone else has a question in a similar problem domain.
The answer is actually very simple.
HttpContext.ApplicationInstance.CompleteRequest()
The above call no longer throws a ThreadAbortException (this changed with .NET 2.0) so you can safely use it to tell the pipeline to halt execution. When the HttpModule exits, the web site proper is bypassed and control goes directly to EndRequest-- exactly what I needed. This was not possible in .NET 1.1 but I don't think there are a lot of 1.1 MVC projects out there ;)
Since you mentioned this was for authentication, you should use the Authorize Attribute. You can use it either at the Class level or the Action level.
[Authorize]
public class HomeController : Controller
{
// All actions will require authorization
}
public class ImageController : Controller
{
public ActionResult PublicImage()
{
}
[Authorize]
public ActionResult ImageRequiringAuth()
{
}
}
For your use case, you may need to inherit from the AuthorizationAttribute, as described in this answer.
I'm using ServiceStack with great results so far, except that dealing with errors is seemingly tricky. If something goes wrong during serialization of a message (because I forgot to add a default constructor to the message for example) all the client gets back is a message that the server had an internal error and a status code of 500. Adding a listener to the HttpApplication.Error event in the Global.asax doesn't work as it never gets hit. Neither does Application_Error. Not only is this insufficient for end user scenarios, it makes debugging these errors very cumbersome as the only way to find out what went wrong is this ugly expression in the Quick Watch:
Encoding.Default.GetString( ((System.IO.MemoryStream)((SyncMemoryStream)((System.Net.HttpWebResponse)(((WebException)ex).Response)).ResponseStream))._buffer)
What I'd like is catch any and all errors on the server side (be it serialization by ServiceStack, or errors on my services) and add the required information to an Errors collection that all my message types have.
See ServiceStack's Validation and Error handling wiki page for more details about error handling and validation in ServiceStack.
At the moment there is no way to handle a serialization exception with Custom logic (although I will now add that on the TODO list :).
If your Response DTO has a ResponseStatus property (i.e. or inherits from IHasResponseStatus), ServiceStack should automatically serialize your exception.
To also get it to serialize your StackTrace set DebugMode to true with SetConfig() in your AppHost.Configure() onload script.