Deep understanding of exception interception in asp.net MVC

Time:2019-11-25

I. Preface

Because the client environment is inconsistent, it may cause unexpected exception errors, so in the project, friendly exception information prompt is very important. In asp.net MVC, it is also very simple to implement exception property interception. You only need to inherit another class (system. Web. MVC. Filterattribute) and an interface (system. Web. MVC. Iexceptionfilter), implement onexception method in the interface, or directly inherit the class system. Web. MVC. Handleerrorattribute provided by MVC.

Let’s have a look at the detailed introduction

II. Implementation of key logic

Inheriting system.web.mvc.handleerrorattribute and overriding onexception method, the main implementation logic code is as follows:

public class HandlerErrorAttribute : HandleErrorAttribute
{
 /// <summary>
 ///An exception occurs in the controller method, which will be called to catch the exception
 /// </summary>
 ///< param name = "context" > provide use < / param >
 public override void OnException(ExceptionContext context)
 {
 WriteLog(context);
 base.OnException(context);
 context.ExceptionHandled = true;
 if (context.Exception is UserFriendlyException)
 {
 context.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
 context.Result = new ContentResult { Content = new AjaxResult { type = ResultType.error, message = context.Exception.Message }.ToJson() };
 }
 else if (context.Exception is NoAuthorizeException)
 {
 context.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
 if (!context.HttpContext.Request.IsAjaxRequest())
 {
 context.HttpContext.Response.RedirectToRoute("Default", new { controller = "Error", action = "Error401", errorUrl = context.HttpContext.Request.RawUrl });
 }
 else
 {
 context.Result = new ContentResult { Content = context.HttpContext.Request.RawUrl };
 }
 }
 else
 {
 context.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
 ExceptionMessage error = new ExceptionMessage(context.Exception);
 var s = error.ToJson();
 if (!context.HttpContext.Request.IsAjaxRequest())
 {
  context.HttpContext.Response.RedirectToRoute("Default", new { controller = "Error", action = "Error500", data = WebHelper.UrlEncode(s) });
 }
 else
 {
  context.Result = new ContentResult { Content = WebHelper.UrlEncode(s) };
 }
 }
 }
 
 /// <summary>
 ///Write log (log4net)
 /// </summary>
 ///< param name = "context" > provide use < / param >
 private void WriteLog(ExceptionContext context)
 {
 if (context == null)
 return;
 if (context.Exception is NoAuthorizeException || context.Exception is UserFriendlyException)
 {
 //Friendly error prompt, unauthorized error prompt, and warning log
 LogHelper.Warn(context.Exception.Message);
 }
 else
 {
 //Unexpected error,
 LogHelper.Error(context.Exception);
 
 ////Todo: write error log to database
 }
 }
}

MVC filter global registration exception blocking:


public class FilterConfig
 {
 public static void RegisterGlobalFilters(GlobalFilterCollection filters)
 {
 filters.Add(new HandlerErrorAttribute());
 }
 }

We can see that context.exception is divided into three types: userfriendleexception, noauthorizeexception or exception; userfriendleexception refers to friendly exception, and the front-end friendly prompts error information. Noauthorizeexception is a 401 unauthorized exception. When the page is not authorized to access, it returns the exception and carries an unauthorized path address. Other exceptions return 500 errors and carry exception information.

III. exception handling

1.401 unauthorized error

Exception definition code:

/// <summary>
///Unauthorized exception
/// </summary>
public class NoAuthorizeException : Exception
{
 public NoAuthorizeException(string message)
 : base(message)
 {
 }
}

Exception code thrown:

Throw new noauthorizeexception ("unauthorized");

Front end UI effect:

2.404 page error not found

There are several ways to deal with the 404 exception of MVC. We use the global.asax global request function to deal with it. Please check the following code


protected void Application_EndRequest()
 {
 if (Context.Response.StatusCode == 404)
 {
 bool isAjax = new HttpRequestWrapper(Context.Request).IsAjaxRequest();
 if (isAjax)
 {
  Response.Clear();
  Response.Write(Context.Request.RawUrl);
 }
 else
 {
  Response.RedirectToRoute("Default", new { controller = "Error", action = "Error404", errorUrl = Context.Request.RawUrl });
 }
 }
 }

Front end UI effect:

3.500 server internal error 

500 definition of exception information object thrown by exception error:

/// <summary>
///Exception error message
/// </summary>
[Serializable]
public class ExceptionMessage
{
 public ExceptionMessage()
 {
 }
 
 /// <summary>
 ///Constructor
 ///Default display exception page
 /// </summary>
 ///< param name = "ex" > exception object < / param >
 public ExceptionMessage(Exception ex)
 :this(ex, true)
 {
 
 }
 /// <summary>
 ///Constructor
 /// </summary>
 ///< param name = "ex" > exception object < / param >
 ///< param name = "isshowexception" > show exception page or not < / param >
 public ExceptionMessage(Exception ex, bool isShowException)
 {
 MsgType = ex.GetType().Name;
 Message = ex.InnerException != null ? ex.InnerException.Message : ex.Message;
 StackTrace = ex.StackTrace.Length > 300 ? ex.StackTrace.Substring(0, 300) : ex.StackTrace;
 Source = ex.Source;
 Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
 Assembly = ex.TargetSite.Module.Assembly.FullName;
 Method = ex.TargetSite.Name;
 
 ShowException = isShowException;
 var request = HttpContext.Current.Request;
 IP = Net.Ip;
 UserAgent = request.UserAgent;
 Path = request.Path;
 HttpMethod = request.HttpMethod;
 }
 /// <summary>
 ///Message type
 /// </summary>
 public string MsgType { get; set; }
 
 /// <summary>
 ///Message content
 /// </summary>
 public string Message { get; set; }
 
 /// <summary>
 ///Request path
 /// </summary>
 public string Path { get; set; }
 
 /// <summary>
 ///Assembly name
 /// </summary>
 public string Assembly { get; set; }
 
 /// <summary>
 ///Abnormal parameters
 /// </summary>
 public string ActionArguments { get; set; }
 
 /// <summary>
 ///Request type
 /// </summary>
 public string HttpMethod { get; set; }
 
 /// <summary>
 ///Exception stack
 /// </summary>
 public string StackTrace { get; set; }
 
 /// <summary>
 ///Anomalous source
 /// </summary>
 public string Source { get; set; }
 
 /// <summary>
 ///Server IP port
 /// </summary>
 public string IP { get; set; }
 
 /// <summary>
 ///Client browser identity
 /// </summary>
 public string UserAgent { get; set; }
 
 
 /// <summary>
 ///Display exception interface
 /// </summary>
 public bool ShowException { get; set; }
 
 /// <summary>
 ///Time of exception
 /// </summary>
 public string Time { get; set; }
 
 /// <summary>
 ///Abnormal occurrence method
 /// </summary>
 public string Method { get; set; }
}

Exception code thrown:

Throw new exception ("error");

Front end UI effect:

4. Userfriendlyexception

Exception definition code:

/// <summary>
///User friendly exception
/// </summary>
public class UserFriendlyException : Exception
{
 public UserFriendlyException(string message)
 : base(message)
 {
 }
}

In the key code of exception interception, we found that the user friendly exception actually returned a result object, ajaxresult,

Definition of ajaxresult object:

/// <summary>
 ///Represents the result of an Ajax operation
 /// </summary>
 public class AjaxResult
 {
 /// <summary>
 ///Get Ajax operation result type
 /// </summary>
 public ResultType type { get; set; }
 
 /// <summary>
 ///Get Ajax operation result code
 /// </summary>
 public int errorcode { get; set; }
 
 /// <summary>
 ///Get message content
 /// </summary>
 public string message { get; set; }
 
 /// <summary>
 ///Get return data
 /// </summary>
 public object resultdata { get; set; }
 }
 /// <summary>
 ///Enumeration representing the result types of Ajax operations
 /// </summary>
 public enum ResultType
 {
 /// <summary>
 ///Message result type
 /// </summary>
 info = 0,
 
 /// <summary>
 ///Success result type
 /// </summary>
 success = 1,
 
 /// <summary>
 ///Warning result type
 /// </summary>
 warning = 2,
 
 /// <summary>
 ///Abnormal result type
 /// </summary>
 error = 3
 }

IV. handling in case of Ajax request exception

In the key code of exception interception, we have seen that if it is an Ajax request, it is to execute different logic. This is because the request of Ajax cannot jump directly through the route of MVC, and the result content must be returned when the request is made

Then, in the front-end Ajax method, we uniformly handle the returned errors. The following is the Ajax encapsulation used in our project, which uniformly handles the abnormal errors.

(function ($) {
 "use strict";
 
 $.httpCode = {
 success: "1",
 fail: "3",
 };
 //Call this method when HTTP communication is abnormal
 $.httpErrorLog = function (msg) {
 console.log('=====>' + new Date().getTime() + '<=====');
 console.log(msg);
 };
 
 //Ajax request error handling
 $.httpError = function (xhr, textStatus, errorThrown) {
 
 if (xhr.status == 401) {
  location.href = "/Error/Error401?errorUrl=" + xhr.responseText;
 }
 
 if (xhr.status == 404) {
  location.href = "/Error/Error404?errorUrl=" + xhr.responseText;
 }
 
 if (xhr.status == 500) {
  location.href = "/Error/Error500?data=" + xhr.responseText;
 }
 };
 
 /*Get request method (asynchronous):
 *URL address, param parameter, callback function before send request, callback function after complete request
 *Considering that get requests usually pass parameters together with URL splicing, param parameters are placed last
 *Return ajaxresult result result object
 */
 $.httpAsyncGet = function (url, callback, beforeSend, complete, param) {
 $.ajax({
  url: url,
  data: param,
  type: "GET",
  dataType: "json",
  async: true,
  cache: false,
  success: function (data) {
  if ($.isFunction(callback)) callback(data);
  },
  error: function (XMLHttpRequest, textStatus, errorThrown) {
  $.httpError(XMLHttpRequest, textStatus, errorThrown);
  },
  beforeSend: function () {
  if (!!beforeSend) beforeSend();
  },
  complete: function () {
  if (!!complete) complete();
  }
 });
 };
 
 /*Get request method (synchronization):
 *URL address, param parameter
 *Return entity data object
 */
 $.httpGet = function (url, param) {
 var res = {};
 $.ajax({
  url: url,
  data: param,
  type: "GET",
  dataType: "json",
  async: false,
  cache: false,
  success: function (data) {
  res = data;
  },
  error: function (XMLHttpRequest, textStatus, errorThrown) {
  $.httpError(XMLHttpRequest, textStatus, errorThrown);
  },
 });
 return res;
 };
 
 /*Post request method (asynchronous):
 *URL address, param parameter, callback function before send request, callback function after complete request
 *Return ajaxresult result result object
 */
 $.httpAsyncPost = function (url, param, callback, beforeSend, complete) {
 $.ajax({
  url: url,
  data: param,
  type: "POST",
  dataType: "json",
  async: true,
  cache: false,
  success: function (data) {
  if ($.isFunction(callback)) callback(data);
  },
  error: function (XMLHttpRequest, textStatus, errorThrown) {
  $.httpError(XMLHttpRequest, textStatus, errorThrown);
  },
  beforeSend: function () {
  if (!!beforeSend) beforeSend();
  },
  complete: function () {
  if (!!complete) complete();
  }
 });
 };
 
 /*Post request method (synchronous):
 *URL address, param parameter, callback回调函数
 *Return entity data object
 */
 $.httpPost = function (url, param, callback) {
 $.ajax({
  url: url,
  data: param,
  type: "POST",
  dataType: "json",
  async: false,
  cache: false,
  success: function (data) {
  if ($.isFunction(callback)) callback(data);
  },
  error: function (XMLHttpRequest, textStatus, errorThrown) {
  $.httpError(XMLHttpRequest, textStatus, errorThrown);
  },
 });
 },
 
 /*Ajax asynchronous encapsulation:
 *Type request type, URL address, param parameter, callback callback function
 *Return entity data object
 */
 $.httpAsync = function (type, url, param, callback) {
 $.ajax({
  url: url,
  data: param,
  type: type,
  dataType: "json",
  async: true,
  cache: false,
  success: function (data) {
  if ($.isFunction(callback)) callback(data);
  },
  error: function (XMLHttpRequest, textStatus, errorThrown) {
  $.httpError(XMLHttpRequest, textStatus, errorThrown);
  },
 });
 };
})(jQuery);

Five, summary

At this point, we found that the exception handling of MVC is really simple. We only need to globally register in the filter, and then rewrite the onexception method to implement the logic. The key is that Ajax requests in the project need to be packaged in a unified way.

Well, the above is the whole content of this article. I hope that the content of this article has some reference learning value for your study or work. If you have any questions, you can leave a message and exchange. Thank you for your support for developepaer.

Recommended Today

Manjaro uses SS method (requires nodejs environment)

Just installed manjaro, need to installshadowsocks-qt5+Proxy SwitchyOmega, but the latest Chrome has long blocked the installation of non Google store CRX channels. Here is my solution, which is troublesome but usable. If you are familiar with NPM commands in nodejs, you won’t find it troublesome, because nodejs is used for compilation. Preparation environment: A VPS […]