网站首页 编程语言 正文
目录
- 一、需求
- 二、案例
- 1、创建工具类
- 1.1、创建日志工具类
- 1.2、创建网络工具类
- 2、创建自定义异常类
- 3、创建控制器
- 4、测试
在上一篇文章中讲解了自定义异常过滤器,这篇文章会结合工作中的真实案例讲解一下如何使用自定义异常过滤器。
一、需求
本案例要实现的功能需求:在发生异常时记录日志,日志内容包括发生异常的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-12-22 Python中排序函数sorted()函数的使用实例_python
- 2022-05-08 ASP.NET MVC对URL匹配操作_实用技巧
- 2022-12-05 numpy中的log和ln函数解读_python
- 2022-08-29 python中内置函数ord()返回字符串的ASCII数值实例详解_python
- 2024-04-08 SpringBoot缓存注解@Cacheable、@CacheEvict和@CachePut
- 2022-07-13 FileInputStream与BufferedInputStream的区别
- 2022-08-20 python3 最常用的三种装饰器语法汇总_python
- 2022-09-14 jQuery实现简单计算器功能_jquery
- 最近更新
-
- 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同步修改后的远程分支
