Three ways to render error pages

Source: Internet
Author: User

Three ways to render error pages

Because an ASP. NET core application is a server application that processes multiple requests at the same time, the exception thrown during processing of a request does not cause the entire application to terminate. For security reasons, in order to avoid the leakage of sensitive information, the client will not get a detailed error message by default, which will undoubtedly increase the difficulty of error correction in the development environment. For production environments, we also want end users to be able to get targeted and friendly error messages based on specific error types. ASP. NET core provides the appropriate middleware to help us present customized error messages, which are defined in the NuGet package "Microsoft.AspNetCore.Diagnostics". Before focusing on these middleware, we are supposed to demonstrate a few simple examples to give readers a general understanding of the role of these middleware. [This article has been synced to the "ASP. NET Core Framework"]

Directory
First, Show developer Exception page
Second, display the custom exception page
Iii. customizing error pages for response status codes

first, Show developer Exception page

In general, if ASP. NET core has an exception when processing a request, it typically returns a response with a status code of "Internal Server Error." In order to avoid the leakage of sensitive information, the detailed error message is not sent to the client as a response, so the client will only get a very generalized error message. As an example of this program, the server throws an exception of type InvalidOperationException when processing each request.

   1:public class Program
   2: {
   3: Public     static void Main ()
   4:     {
   5:         New Webhostbuilder ()
   6:             . Usekestrel ()
   7:             . Configure (app = App. Run (context = task.fromexception (new InvalidOperationException ("Manually thrown exception ...")))
   8:             . Build ()
   9:             . Run ();
  Ten:     }
  11:}

When we use the browser to access this app, we always get the error page as shown. It can be seen that this page simply tells us that the target application is currently unable to process this request, except for the response status code ("HTTP ERROR 500") provided, and it does not provide any error-correcting errors that are useful for error correction.

Then one might think that although no detailed error message is displayed on the browser, it may be hidden in the HTTP response message received. For this request to be released through the browser, the response content is as follows, we will find that the response message does not have a body part, a limited number of headers also does not host any error-related information.

   1:http/1.1 Internal Server Error
   2:date:fri, 23:42:18 GMT
   3:content-length:0
   4:server:kestrel

As the application is not interrupted, no targeted error messages are displayed on the browser, and how exactly does the developer pinpoint the line of code that is the source of the error when making error-checking errors? Specifically, we have two more solutions, one is to take advantage of the log , because any errors that ASP. NET core will be written to when processing the request. So we can get a write error log by registering the appropriate loggerprovider (such as registering a consoleloggerprovider to write the log directly to the console of the host app).

Another solution is to display an error page that contains the appropriate information for the error, as this page is shown to the developer in the development environment, so we refer to this page as the developer Exception page (Developer Exception pages). The automatic rendering of the page is done using a middleware called Developerexceptionpagemiddleware , and we can call the Applicationbuilder extension method Usedeveloperexceptionpage to register this middleware.

   1:public class Program
   2: {
   3: Public     static void Main ()
   4:     {
   5:         New Webhostbuilder ()
   6:             . Usekestrel ()
   7:             . Configure (app = App
   8:                 . Usedeveloperexceptionpage ()
   9:                 . Run (context = task.fromexception (new InvalidOperationException ("Manually thrown exception ...")))
  Ten:             . Build ()
  One:             . Run ();
  12:}
  13:}

Once the Developerexceptionpagemiddleware middleware is registered, the ASP. NET core application will appear directly on the browser in the form of the exception information that the request appears, and we can see almost all the error messages on this page. Includes the type of exception, message and stack information, and so on.

The developer Exception page displays information related to the current request context in the form shown in addition to the information associated with the thrown exception, including all query strings carried by the current request URL, all request headers, and the contents of the cookie. Such exhaustive information will undoubtedly greatly help developers to find out the root of the error as quickly as possible.

Error pages rendered through Developerexceptionpagemiddleware middleware are for developers only, and detailed error messages tend to carry sensitive information, so it's important to remember that the middleware can only be registered in the development environment , The code snippet shown below shows the correct registration method for Developerexceptionpagemiddleware middleware.

   1:new Webhostbuilder ()
   2:     . Usestartup<startup> ()
   3: ...     
   
   5:public class Startup
   6: {
   7: Public     void Configure (Iapplicationbuilder app, Ihostingenvironment env)
   8:     {
   9:         if (env. Isdevelopment ())
  Ten:         {
  One:             app. Usedeveloperexceptionpage ();
  :         }
  :     }
  14:}
Second, display the custom exception page

Developerexceptionpagemiddleware Middleware provides developers with great convenience for error diagnosis by rendering exception details and content based on the current request directly on the errors page. But in a production environment, we tend to present a custom error page for the end user, which can be achieved by registering another middleware called Exceptionhandlermiddleware . As the name implies, this middleware is designed to provide an exception handler (Exception Handler) to handle thrown exceptions. In fact, this so-called exception handler is a delegate object of type Requestdelegate, and the Exceptionhandlermiddleware middleware captures the thrown exception and uses it to respond to the current request.

It is also an example of an application created above that will always throw a InvalidOperationException exception. We call the Applicationbuilder extension method as follows Useexceptionhandler Register the Exceptionhandlermiddleware middleware above. This extension method has a parameter of type exceptionhandleroptions, and its Exceptionhandler property returns the Requestdelegate object that is the exception handler.

   1:public class Program
   2: {
   3: Public     static void Main ()
   4:     {
   5:         Requestdelegate handler = Async context = await context. Response.writeasync ("Unhandled exception occurred!");
   
   7:         new Webhostbuilder ()
   8:             . Usekestrel ()
   9:             . Configure (app = App. Useexceptionhandler (new Exceptionhandleroptions {exceptionhandler = handler})
  Ten:             . Run (context = task.fromexception (new InvalidOperationException ("Manually thrown exception ...")))
  One:             . Build ()
  A:             . Run ();
  :     }
  14:}

As shown in the code snippet above, this requestdelegate as an exception handler simply adds a simple error message ("Unhandled exception occurred!" ) as the content of the response. When we use the browser to access the app, this custom error message will be presented directly to the browser in the form of 4.

Finally, the exception handler is a delegate object of type Requestdelegate, and Applicationbuilder has the ability to create this delegate object. Specifically, we can register the corresponding middleware on a Applicationbuilder object based on the need for exception handling. And finally use this applicationbuilder to create a Requestdelegate object as an exception handler based on the registered middleware. If exception handling needs to be done through one or more middleware, we can call another Useexceptionhandler method overload as follows. The parameter type of this method is Action<iapplicationbuilder>, and we call its run method to register a middleware to respond to a simple error message.

   1:public class Program
   2: {
   3: Public     static void Main ()
   4:     {        
   5:         New Webhostbuilder ()
   6:             . Usekestrel ()
   7:             . Configure (app = App. Useexceptionhandler (Builder=>builder. Run (Async context = await context. Response.writeasync ("Unhandled Exception occurred!")))
   8:             . Run (context = task.fromexception (new InvalidOperationException ("Manually thrown exception ...")))
   9:         . Build ()
  Ten:         . Run ();
  One:     }
  12:}

Both of these forms of exception handling are provided by providing a Requestdelegate delegate object to handle the thrown exception and to complete the final response. If the application has already set an error page, and the error page has a fixed path, then we do not need to provide this Requestdelegate object for exception handling, and only need to redirect to the wrong page point to the path. This use of service end multiplicity Directional exception handling can be done in the form of calling another Useexceptionhandler method overload, the parameter of this method is the target path of the redirect ("/error"), We have registered a routing response for this path to respond to custom error messages.

   1:public class Program
   2: {
   3: Public     static void Main ()
   4:     {
   5:         New Webhostbuilder ()
   6:             . Usekestrel ()
   7:             . Configureservices (Svcs=>svcs. Addrouting ())
   8:             . Configure (app = App
   9:                 . Useexceptionhandler ("/error")
  Ten:                 . Userouter (Builder=>builder. MapRoute ("Error", async context = await context.) Response.writeasync ("Unhandled Exception occurred!")))
  One:                 . Run (context = task.fromexception (new InvalidOperationException ("Manually thrown exception ...")))
  A:         . Build ()
  :         . Run ();
  :     }
  15:}
iii. Customizing error pages for response status codes

Because Web applications use HTTP communication protocols, we should cater to the HTTP standard as low as possible and apply the semantics defined in the protocol specification to the application. For exception or error semantic expression in the HTTP protocol level is mainly reflected in the response message status code, specifically, HTTP communication errors are broadly divided into the following two types:

    • Client Error: Indicates that the server could not process the request correctly because the client provided incorrect request information, and the response status code range is between 400~499.
    • Service-side error: Indicates that the server has an error during processing of the request due to its own problem, and the response status code is between 500~509.

It is because the response status code is the most important expression for error or exception semantics, so in many cases we need to customize the displayed error message for different response status codes. Customizing the error page for the response status code can be achieved with a middleware of type statuscodepagesmiddleware , and we can call Applicationbuilder to register the middleware with the appropriate extension method.

Developerexceptionpagemiddleware and Exceptionhandlermiddleware middleware are called when exceptions are thrown during subsequent request processing. The premise of Statuscodepagesmiddleware being invoked is that an error response status code (range between 400~599) is generated in the subsequent request assistant process. If we just want to display a unified error page, we can call the extension method Usestatuscodepages as follows to register the middleware, the two parameters passing in the method represent the media type and the main content of the response.

   1:public class Program
   2: {
   3: Public     static void Main ()
   4:     {        
   5:         New Webhostbuilder ()
   6:             . Usekestrel ()
   7:             . Configure (App=>app
   8:                 . Usestatuscodepages ("Text/plain", "Error occurred ({0})")
   9:                 . Run (context=> task.run () =>context. Response.statuscode = 500)))
  Ten:         . Build ()
  One:         . Run ();
  :     }
  13:}

As shown in the code snippet above, the application will always set the response status code to 500 when processing the request, so the final response will be provided by the registered Statuscodepagesmiddleware middleware. When we call the Usestatuscodepages method, we set the media type of the response to "Text/plain" and use a simple error message as the principal content of the response. It is worth mentioning that, as a response to the content of the string can contain a placeholder ({0}), the Statuscodepagesmiddleware middleware will eventually use the current response status code to replace it. If we use the browser to access this app, we will get the error page as shown.

If we want to display different error pages for different error status codes, then we need to implement the specific request processing logic in a status code error handler and eventually provide it to the Statuscodepagesmiddleware middleware. This so-called status code error handler is represented by a delegate object of type Func<statuscodecontext, task>, as the input Statuscodecontext object is the encapsulation of the current HttpContext, While hosting some other options related to error handling, we'll cover this type in more detail in subsequent sections of this series.

For this application, it is always random to select an integer between 400~599 as the status code of the response, so the response returned by the client is always provided by the registered Statuscodepagesmiddleware middleware. When we call another Usestatuscodepages method overload, we specify a func<statuscodecontext for the registered middleware, and the Task> object as the status code error handler.

   1:public class Program
   2: {
   3:private static Random _random = new Random ();
   
   5: Public     static void Main ()
   6:     {
   7:         func<statuscodecontext, task> handler = Async context = {
   8:             var response = context. Httpcontext.response;
   9:             if (response. StatusCode < 500)
  Ten:             {
  One:                 await response. WriteAsync ($ "Client error ({response). StatusCode});
  :             }
  :             Else
  :             {
  :                 await response. WriteAsync ($ "Server error ({response. StatusCode});
  :             }
  :         };
  :         new Webhostbuilder ()
  :             . Usekestrel ()
  A:             . Configure (app = App
  A:                 . Usestatuscodepages (Handler)
  A:                 . Run (context = task.run () = context. Response.statuscode = _random. Next (400,599))))
  At:             . Build ()
  A:             . Run ();
  :     }
  26:}

We specify a status code error handler that, when processing a request, divides the error into two types of client and server errors based on the response status code, and selects the targeted error message as the response content. When we use the browser to access this app, the error message displayed will be determined by the response status code.

In the world of ASP. NET core, the processing of requests is always represented as a Requestdelegate object. If the requested processing needs to be done with one or more middleware, we can register them on the Applicationbuilder object and use it to convert the middleware pipeline into a Requestdelegate object. The Usestatuscodepage method for registering the Statuscodepagesmiddleware middleware also has another overload that allows us to create a Requestdelegate object in this way to complete the final request processing. So the application shown above can be changed into the following form.

   1:public class Program
   2: {
   3:     private static random _random = new Random ();
   4: Public     static void Main ()
   5:     {
   6:         Requestdelegate handler = Async context =
   7:         {
   8:             var response = context. Response;
   9:             if (response. StatusCode < 500)
  Ten:             {
  One:                 await response. WriteAsync ($ "Client error ({response). StatusCode});
  :             }
  :             Else
  :             {
  :                 await response. WriteAsync ($ "Server error ({response. StatusCode});
  :             }
  :         };
  :         new Webhostbuilder ()
  :             . Usekestrel ()
  A:             . Configure (app = App
  A:                 . Usestatuscodepages (Builder=>builder. Run (handler))
  A:                 . Run (context = task.run () = context. Response.statuscode = _random. Next (400, 599)))
  At:             . Build ()
  A:             . Run ();
  :     }
  26:}

Error handling for ASP. NET core applications [1]: Three ways to render error pages
Error handling for ASP. NET core applications [2]:developerexceptionpagemiddleware middleware
Error handling for ASP. NET core applications [3]:exceptionhandlermiddleware middleware
Error handling for ASP. NET core applications [4]:statuscodepagesmiddleware middleware

Three ways to render error pages

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.