網站首頁 編程語言 正文
在上一篇文章中講解了自定義異常過濾器,這篇文章會結合工作中的真實案例講解一下如何使用自定義異常過濾器。
一、需求
本案例要實現的功能需求:在發生異常時記錄日志,日志內容包括發生異常的Controller名稱、Action名稱、使用瀏覽器類型和版本等。
二、案例
1、創建工具類
首先創建項目中需要使用的工具類。
1.1、創建日志工具類
在案例中使用Log4net來記錄日志。首先要添加對Log4net的引用,直接在NuGet里面搜索Log4net,然后安裝即可。
日志消息實體類代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MVCCuetomerExcepFilterDemo.Models { ////// 日志消息實體類 /// public class LogMessageEntity { ////// 操作時間 /// public DateTime OperationTime { get; set; } ////// Url地址 /// public string Url { get; set; } ////// 類名 /// public string Class { get; set; } ////// IP /// public string Ip { get; set; } ////// 主機 /// public string Host { get; set; } ////// 瀏覽器 /// public string Browser { get; set; } ////// 操作人 /// public string UserName { get; set; } ////// 內容 /// public string Content { get; set; } ////// 異常信息 /// public string ExceptionInfo { get; set; } ////// 異常來源 /// public string ExceptionSource { get; set; } ////// 異常信息備注 /// public string ExceptionRemark { get; set; } } }
創建日志級別枚舉類型,分別對應Log4net中的日志級別,代碼如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Web; namespace MVCCuetomerExcepFilterDemo.Models.Enums { ////// 日志級別 /// public enum LogLevel { ////// 錯誤 /// [Description("錯誤")] Error, ////// 警告 /// [Description("警告")] Warning, ////// 信息 /// [Description("信息")] Info, ////// 調試 /// [Description("調試")] Debug } }
創建一個對日志格式進行格式化的類,代碼如下:
using MVCCuetomerExcepFilterDemo.Models; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; namespace MVCCuetomerExcepFilterDemo.Util { ////// 日志格式器 /// public class LogFormat { ////// 生成錯誤 /// /// 對象 ///public string ErrorFormat(LogMessageEntity logMessage) { StringBuilder strInfo = new StringBuilder(); strInfo.Append("1. 錯誤: >> 操作時間: " + logMessage.OperationTime + " 操作人: " + logMessage.UserName + " \r\n"); strInfo.Append("2. 地址: " + logMessage.Url + " \r\n"); strInfo.Append("3. 類名: " + logMessage.Class + " \r\n"); strInfo.Append("4. Ip : " + logMessage.Ip + " 主機: " + logMessage.Host + " 瀏覽器: " + logMessage.Browser + " \r\n"); strInfo.Append("5. 內容: " + logMessage.Content + "\r\n"); strInfo.Append("-----------------------------------------------------------------------------------------------------------------------------\r\n"); return strInfo.ToString(); } /// /// 生成警告 /// /// 對象 ///public string WarnFormat(LogMessageEntity logMessage) { StringBuilder strInfo = new StringBuilder(); strInfo.Append("1. 警告: >> 操作時間: " + logMessage.OperationTime + " 操作人: " + logMessage.UserName + " \r\n"); strInfo.Append("2. 地址: " + logMessage.Url + " \r\n"); strInfo.Append("3. 類名: " + logMessage.Class + " \r\n"); strInfo.Append("4. Ip : " + logMessage.Ip + " 主機: " + logMessage.Host + " 瀏覽器: " + logMessage.Browser + " \r\n"); strInfo.Append("5. 內容: " + logMessage.Content + "\r\n"); strInfo.Append("-----------------------------------------------------------------------------------------------------------------------------\r\n"); return strInfo.ToString(); } /// /// 生成信息 /// /// 對象 ///public string InfoFormat(LogMessageEntity logMessage) { StringBuilder strInfo = new StringBuilder(); strInfo.Append("1. 信息: >> 操作時間: " + logMessage.OperationTime + " 操作人: " + logMessage.UserName + " \r\n"); strInfo.Append("2. 地址: " + logMessage.Url + " \r\n"); strInfo.Append("3. 類名: " + logMessage.Class + " \r\n"); strInfo.Append("4. Ip : " + logMessage.Ip + " 主機: " + logMessage.Host + " 瀏覽器: " + logMessage.Browser + " \r\n"); strInfo.Append("5. 內容: " + logMessage.Content + "\r\n"); strInfo.Append("-----------------------------------------------------------------------------------------------------------------------------\r\n"); return strInfo.ToString(); } /// /// 生成調試 /// /// 對象 ///public string DebugFormat(LogMessageEntity logMessage) { StringBuilder strInfo = new StringBuilder(); strInfo.Append("1. 調試: >> 操作時間: " + logMessage.OperationTime + " 操作人: " + logMessage.UserName + " \r\n"); strInfo.Append("2. 地址: " + logMessage.Url + " \r\n"); strInfo.Append("3. 類名: " + logMessage.Class + " \r\n"); strInfo.Append("4. Ip : " + logMessage.Ip + " 主機: " + logMessage.Host + " 瀏覽器: " + logMessage.Browser + " \r\n"); strInfo.Append("5. 內容: " + logMessage.Content + "\r\n"); strInfo.Append("-----------------------------------------------------------------------------------------------------------------------------\r\n"); return strInfo.ToString(); } /// /// 生成異常信息 /// /// 對象 ///public string ExceptionFormat(LogMessageEntity logMessage) { StringBuilder strInfo = new StringBuilder(); strInfo.Append("1. 調試: >> 操作時間: " + logMessage.OperationTime + " 操作人: " + logMessage.UserName + " \r\n"); strInfo.Append("2. 地址: " + logMessage.Url + " \r\n"); strInfo.Append("3. 類名: " + logMessage.Class + " \r\n"); strInfo.Append("4. 主機: " + logMessage.Host + " Ip : " + logMessage.Ip + " 瀏覽器: " + logMessage.Browser + " \r\n"); strInfo.Append("5. 異常: " + logMessage.ExceptionInfo + "\r\n"); //strInfo.Append("6. 來源: " + logMessage.ExceptionSource + "\r\n"); //strInfo.Append("7. 實例: " + logMessage.ExceptionRemark + "\r\n"); strInfo.Append("-----------------------------------------------------------------------------------------------------------------------------\r\n"); return strInfo.ToString(); } } }
創建日志類,代碼如下:
using log4net; using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace MVCCuetomerExcepFilterDemo.Util { ////// 日志 /// public class Log { private ILog logger; public Log(ILog log) { this.logger = log; } public void Debug(object message) { this.logger.Debug(message); } public void Error(object message) { this.logger.Error(message); } public void Info(object message) { this.logger.Info(message); } public void Warn(object message) { this.logger.Warn(message); } } }
創建日志初始化類,代碼如下:
using log4net; using MVCCuetomerExcepFilterDemo.Models; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Web; namespace MVCCuetomerExcepFilterDemo.Util { ////// 日志初始化 /// public class LogFactory { static LogFactory() { FileInfo configFile = new FileInfo(HttpContext.Current.Server.MapPath("/XmlConfig/log4net.config")); log4net.Config.XmlConfigurator.Configure(configFile); } public static Log GetLogger(Type type) { return new Log(LogManager.GetLogger(type)); } public static Log GetLogger(string str) { return new Log(LogManager.GetLogger(str)); } } }
最后添加log4net的配置文件:
1.2、創建網絡工具類
該工具幫助類用于獲取IP、瀏覽器信息等內容,代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Web; namespace MVCCuetomerExcepFilterDemo.Util { ////// 網絡操作幫助類 /// public class NetHelper { #region Ip(獲取Ip) ////// 獲取Ip /// public static string Ip { get { var result = string.Empty; if (HttpContext.Current != null) result = GetWebClientIp(); if (string.IsNullOrWhiteSpace(result)) result = GetLanIp(); return result; } } ////// 獲取Web客戶端的Ip /// private static string GetWebClientIp() { var ip = GetWebRemoteIp(); foreach (var hostAddress in Dns.GetHostAddresses(ip)) { if (hostAddress.AddressFamily == AddressFamily.InterNetwork) return hostAddress.ToString(); } return string.Empty; } ////// 獲取Web遠程Ip /// private static string GetWebRemoteIp() { return HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] ?? HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"]; } ////// 獲取局域網IP /// private static string GetLanIp() { foreach (var hostAddress in Dns.GetHostAddresses(Dns.GetHostName())) { if (hostAddress.AddressFamily == AddressFamily.InterNetwork) return hostAddress.ToString(); } return string.Empty; } #endregion #region Host(獲取主機名) ////// 獲取主機名 /// public static string Host { get { return HttpContext.Current == null ? Dns.GetHostName() : GetWebClientHostName(); } } ////// 獲取Web客戶端主機名 /// private static string GetWebClientHostName() { if (!HttpContext.Current.Request.IsLocal) return string.Empty; var ip = GetWebRemoteIp(); var result = Dns.GetHostEntry(IPAddress.Parse(ip)).HostName; if (result == "localhost.localdomain") result = Dns.GetHostName(); return result; } #endregion #region Browser(獲取瀏覽器信息) ////// 獲取瀏覽器信息 /// public static string Browser { get { if (HttpContext.Current == null) return string.Empty; var browser = HttpContext.Current.Request.Browser; return string.Format("{0} {1}", browser.Browser, browser.Version); } } #endregion } }
2、創建自定義異常類
上篇文章中講過了,要創建自定義異常類,只需要創建一個繼承自HandleErrorAttribute的類,并重寫OnException方法即可,自定義異常類代碼如下:
using MVCCuetomerExcepFilterDemo.Models; using MVCCuetomerExcepFilterDemo.Util; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MVCCuetomerExcepFilterDemo.Extension { ////// 錯誤日志(Controller發生異常時會執行這里) /// public class ExceptionFilters : HandleErrorAttribute { public override void OnException(ExceptionContext filterContext) { WriteLog(filterContext); base.OnException(filterContext); filterContext.ExceptionHandled = true; filterContext.HttpContext.Response.StatusCode = 200; } ////// 寫入日志(log4net) /// /// 提供使用 private void WriteLog(ExceptionContext context) { if (context == null) return; var log = LogFactory.GetLogger(context.Controller.ToString()); Exception Error = context.Exception; LogMessageEntity logMessage = new LogMessageEntity(); logMessage.OperationTime = DateTime.Now; logMessage.Url = HttpContext.Current.Request.RawUrl; logMessage.Class = context.Controller.ToString(); logMessage.Ip = NetHelper.Ip; logMessage.Host = NetHelper.Host; logMessage.Browser = NetHelper.Browser; // 這里為了方便直接用默認的,真實案例中不能這樣寫 logMessage.UserName = "admin"; if (Error.InnerException == null) { logMessage.ExceptionInfo = Error.Message; } else { logMessage.ExceptionInfo = Error.InnerException.Message; } string strMessage = new LogFormat().ExceptionFormat(logMessage); log.Error(strMessage); } } }
3、創建控制器
控制器里面有一個LogOn登錄的方法,代碼如下:
using MVCCuetomerExcepFilterDemo.Extension; using MVCCuetomerExcepFilterDemo.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Security; namespace MVCCuetomerExcepFilterDemo.Controllers { public class AccountController : Controller { // GET: Account public ActionResult Index() { return View(); } ////// 登錄成功顯示的視圖 /// ///public ActionResult Welcome() { return View(); } /// /// 顯示登錄視圖 /// ///public ActionResult LogOn() { LogOnViewModel model = new LogOnViewModel(); return View(model); } /// /// 處理用戶點擊登錄提交回發的表單 /// /// ///[HttpPost] [ExceptionFilters] public ActionResult LogOn(LogOnViewModel model) { try { string userName = model.UserName.Trim(); int password = Convert.ToInt32(model.Password); // 用戶名是admin,密碼是123456表示驗證通過 if (userName.Equals("admin")&&password.Equals(123456)) { // 判斷是否勾選了記住我 if (model.RememberMe) { //2880分鐘有效期的cookie FormsAuthentication.SetAuthCookie(model.UserName, true); } else { //會話cookie FormsAuthentication.SetAuthCookie(model.UserName, false); } // 跳轉到Account控制器的Welcome方法 return RedirectToAction("Welcome"); } else { return View(model); } } catch (Exception ex) { // 拋出異常 throw; } } } }
4、測試
在控制器代碼中,如果輸入的用戶名是admin,密碼是123456就通過,然后顯示Welcome視圖,如果密碼轉換失敗的時候就記錄異常日志。
首先輸入正確的用戶名和密碼:
點擊登錄,然后顯示Welcome視圖:
這次輸入錯誤的密碼:
再次點擊登錄,這時查看生成的日志:
在上面的代碼中,我們在LogOn()方法上面使用了ExceptionFilters這個特性,這樣在控制器發生異常的時候就會進入ExceptionFilters自定義異常類,然后記錄日志。但是這樣有一個問題:使用這種方式要再每個action方法上面都添加該特性,如果action方法比較多,寫起來也是很煩的,那么有沒有什么好的辦法呢?可以在控制器上面添加ExceptionFilters特性,這樣就是針對整個控制器里面的action了。那么還有沒有更簡潔的辦法。看App_Start文件夾下面的FilterConfig定義:
using MVCCuetomerExcepFilterDemo.Extension; using System.Web; using System.Web.Mvc; namespace MVCCuetomerExcepFilterDemo { public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { filters.Add(new HandleErrorAttribute()); } } }
可以看到這里是添加的HandleErrorAttribute類,如果換成自定義的異常類會如何呢?修改后的FilterConfig文件如下:
using MVCCuetomerExcepFilterDemo.Extension; using System.Web; using System.Web.Mvc; namespace MVCCuetomerExcepFilterDemo { public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //filters.Add(new HandleErrorAttribute()); // 使用自定義異常類 filters.Add(new ExceptionFilters()); } } }
AccountController控制器代碼修改如下:
using MVCCuetomerExcepFilterDemo.Extension; using MVCCuetomerExcepFilterDemo.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Security; namespace MVCCuetomerExcepFilterDemo.Controllers { public class AccountController : Controller { // GET: Account public ActionResult Index() { return View(); } ////// 登錄成功顯示的視圖 /// ///public ActionResult Welcome() { return View(); } /// /// 顯示登錄視圖 /// ///public ActionResult LogOn() { LogOnViewModel model = new LogOnViewModel(); return View(model); } /// /// 處理用戶點擊登錄提交回發的表單 /// /// ///[HttpPost] // [ExceptionFilters] public ActionResult LogOn(LogOnViewModel model) { try { string userName = model.UserName.Trim(); int password = Convert.ToInt32(model.Password); // 用戶名是admin,密碼是123456表示驗證通過 if (userName.Equals("admin")&&password.Equals(123456)) { // 判斷是否勾選了記住我 if (model.RememberMe) { //2880分鐘有效期的cookie FormsAuthentication.SetAuthCookie(model.UserName, true); } else { //會話cookie FormsAuthentication.SetAuthCookie(model.UserName, false); } // 跳轉到Account控制器的Welcome方法 return RedirectToAction("Welcome"); } else { return View(model); } } catch (Exception ex) { // 拋出異常 throw; } } } }
這樣發生異常的時候就會自動進入自定義異常類了,然后記錄日志。
原文鏈接:https://www.cnblogs.com/dotnet261010/p/10856440.html
相關推薦
- 2022-03-03 記一次瀏覽器SameSite策略更新,導致接口 Failed to load response da
- 2022-10-03 React如何實現全屏監聽Esc鍵_React
- 2022-12-10 C++?Boost?Spirit精通教程_C 語言
- 2023-01-19 python圖形界面教程Tkinter詳解_python
- 2022-09-22 elementui select選擇器獲取選中拿到當前對象
- 2022-10-30 Android常用定時器的實現方式_Android
- 2022-08-20 如何利用python實現Simhash算法_python
- 2022-05-26 Python入門必讀的if語句嵌套方法_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支