C#组件系列——又一款日志组件:Elmah的学习和分享
2017-08-24 15:57
495 查看
阅读目录
一、组件介绍
二、组件安装使用
1、安装组件
2、配置组件
3、测试效果
三、功能介绍
1、将日志信息保存到数据库
2、程序“吃掉”异常
3、组件权限问题
四、总结
正文
前言:好久没动笔了,都有点生疏,12月都要接近尾声,可是这月连一篇的产出都没有,不能坏了“规矩”,今天还是来写一篇。最近个把月确实很忙,不过每天早上还是会抽空来园子里逛逛。一如既往,园子里每年这个时候都有大把的年终总结、回忆过去展望未来之类的文章。博主是没时间写总结了,要学的东西太多。关于Vue的系列一定要抽时间补上。最近刚用了一个日志组件Elmah,比较适合开发阶段异常信息的快速定位与追溯,有兴趣的跟着博主一起来看看吧。
本文原创地址:http://www.cnblogs.com/landeanfen/p/6221403.html
回到顶部
1、ELMAH的使用更加简单,它甚至不用写一句代码,只需要引入dll,然后在Web.config里面配置相应的节点即可;
2、按照网上的说法,ELMAH是一种“可拔插式”的组件,即在一个运行的项目里面我们可以随意轻松加入日志功能,或者移除日志功能;
3、ELMAH组件自带界面,不用写任何代码,即可查看异常日志的界面,轻松找到当前异常的详细信息;和web的结合更加紧密;
4、组件提供了一个用于集中记录和通知错误日志的机制,通过邮件的机制通知错误信息给相关人员。
回到顶部
CreateElmah.sql
做了以上三步之后,程序里面的异常就能记录到数据库里面,程序再次启动的时候会自动从数据库里面去取对应的信息。
回到顶部
这就是异常捕获器统一处理异常,既然这里标识了异常已经处理过,那么组件肯定不会再次处理。可是有些情况下,我们需要处理某些自定义异常,而对于系统异常我们还是希望组件能够记录,这种情况下怎么办呢?其实很简单,这里只需要判断一下,如果是自定义异常信息,这里就加上 filterContext.ExceptionHandled = true; 这一句,而对于其他系统异常,则统一加上这一句即可。这里还是做一个简单的演示供需要的园友参考。
满足一定条件则抛出自定义异常
然后再全局异常处理里面
这样就能达到我们系统异常记录,自定义异常不记录的目的了。
回到顶部
回到顶部
本文原创出处:http://www.cnblogs.com/landeanfen/
欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利
一、组件介绍
二、组件安装使用
1、安装组件
2、配置组件
3、测试效果
三、功能介绍
1、将日志信息保存到数据库
2、程序“吃掉”异常
3、组件权限问题
四、总结
正文
前言:好久没动笔了,都有点生疏,12月都要接近尾声,可是这月连一篇的产出都没有,不能坏了“规矩”,今天还是来写一篇。最近个把月确实很忙,不过每天早上还是会抽空来园子里逛逛。一如既往,园子里每年这个时候都有大把的年终总结、回忆过去展望未来之类的文章。博主是没时间写总结了,要学的东西太多。关于Vue的系列一定要抽时间补上。最近刚用了一个日志组件Elmah,比较适合开发阶段异常信息的快速定位与追溯,有兴趣的跟着博主一起来看看吧。
本文原创地址:http://www.cnblogs.com/landeanfen/p/6221403.html
回到顶部
一、组件介绍
ELMAH的全称是The Error Logging Modules And Handlers,翻译过来是错误日志模块和处理。顾名思义,就是一个日志的拦截和处理组件,说到.net的日志组件,大家的第一反应该是Log4Net、NLog等这些东西,关于Log4Net和NLog,可以说是.net日志组件里面使用最为广泛的组件了,它们功能强大、使用方便。相比它们:1、ELMAH的使用更加简单,它甚至不用写一句代码,只需要引入dll,然后在Web.config里面配置相应的节点即可;
2、按照网上的说法,ELMAH是一种“可拔插式”的组件,即在一个运行的项目里面我们可以随意轻松加入日志功能,或者移除日志功能;
3、ELMAH组件自带界面,不用写任何代码,即可查看异常日志的界面,轻松找到当前异常的详细信息;和web的结合更加紧密;
4、组件提供了一个用于集中记录和通知错误日志的机制,通过邮件的机制通知错误信息给相关人员。
回到顶部
二、组件安装使用
回到顶部1、安装组件
Elmah的安装使用同样也很简单,我们万能的Nuget帮我们一键搞定。CREATE TABLE dbo.ELMAH_Error ( ErrorId UNIQUEIDENTIFIER NOT NULL, Application NVARCHAR(60) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, Host NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, Type NVARCHAR(100) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, Source NVARCHAR(60) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, Message NVARCHAR(500) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, [User] NVARCHAR(50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL, StatusCode INT NOT NULL, TimeUtc DATETIME NOT NULL, Sequence INT IDENTITY (1, 1) NOT NULL, AllXml NTEXT COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO ALTER TABLE dbo.ELMAH_Error WITH NOCHECK ADD CONSTRAINT PK_ELMAH_Error PRIMARY KEY NONCLUSTERED ( ErrorId ) ON [PRIMARY] GO ALTER TABLE dbo.ELMAH_Error ADD CONSTRAINT DF_ELMAH_Error_ErrorId DEFAULT (newid()) FOR [ErrorId] GO CREATE NONCLUSTERED INDEX IX_ELMAH_Error_App_Time_Seq ON dbo.ELMAH_Error ( [Application] ASC, [TimeUtc] DESC, [Sequence] DESC ) ON [PRIMARY] GO SET QUOTED_IDENTIFIER ON GO SET ANSI_NULLS ON GO CREATE PROCEDURE dbo.ELMAH_GetErrorXml ( @Application NVARCHAR(60), @ErrorId UNIQUEIDENTIFIER ) AS SET NOCOUNT ON SELECT AllXml FROM ELMAH_Error WHERE ErrorId = @ErrorId AND Application = @Application GO SET QUOTED_IDENTIFIER OFF GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO SET ANSI_NULLS ON GO CREATE PROCEDURE dbo.ELMAH_GetErrorsXml ( @Application NVARCHAR(60), @PageIndex INT = 0, @PageSize INT = 15, @TotalCount INT OUTPUT ) AS SET NOCOUNT ON DECLARE @FirstTimeUTC DateTime DECLARE @FirstSequence int DECLARE @StartRow int DECLARE @StartRowIndex int -- Get the ID of the first error for the requested page SET @StartRowIndex = @PageIndex * @PageSize + 1 SET ROWCOUNT @StartRowIndex SELECT @FirstTimeUTC = TimeUTC, @FirstSequence = Sequence FROM ELMAH_Error WHERE Application = @Application ORDER BY TimeUTC DESC, Sequence DESC -- Now set the row count to the requested page size and get -- all records below it for the pertaining application. SET ROWCOUNT @PageSize SELECT @TotalCount = COUNT(1) FROM ELMAH_Error WHERE Application = @Application SELECT errorId, application, host, type, source, message, [user], statusCode, CONVERT(VARCHAR(50), TimeUtc, 126) + 'Z' time FROM ELMAH_Error error WHERE Application = @Application AND TimeUTC <= @FirstTimeUTC AND Sequence <= @FirstSequence ORDER BY TimeUTC DESC, Sequence DESC FOR XML AUTO GO SET QUOTED_IDENTIFIER OFF GO SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO SET ANSI_NULLS ON GO CREATE PROCEDURE dbo.ELMAH_LogError ( @ErrorId UNIQUEIDENTIFIER, @Application NVARCHAR(60), @Host NVARCHAR(30), @Type NVARCHAR(100), @Source NVARCHAR(60), @Message NVARCHAR(500), @User NVARCHAR(50), @AllXml NTEXT, @StatusCode INT, @TimeUtc DATETIME ) AS SET NOCOUNT ON INSERT INTO ELMAH_Error ( ErrorId, Application, Host, Type, Source, Message, [User], AllXml, StatusCode, TimeUtc ) VALUES ( @ErrorId, @Application, @Host, @Type, @Source, @Message, @User, @AllXml, @StatusCode, @TimeUtc ) GO SET QUOTED_IDENTIFIER OFF GO SET ANSI_NULLS ON GO
CreateElmah.sql
做了以上三步之后,程序里面的异常就能记录到数据库里面,程序再次启动的时候会自动从数据库里面去取对应的信息。
回到顶部
2、程序“吃掉”异常
如果你反编译elmah组件,你会它的原理其实就是通过配置的方式通过HttpModule注册应用程序的Error事件,然后统一处理记录。既然是注册的Application_Error事件,那么肯定就存在某些情况会吃掉异常。(1)在程序里面try...catch...
这种情况很好理解,如果你再代码里面显示的声明了try...catch那么异常肯定不会进到Application_Error事件里面去,组件也不会记录异常。(2)在异常捕获器里面处理了异常
除了使用try吃掉异常之外,很多系统里面都会使用异常捕获器去统一捕获异常,如果再异常捕获器里面设置过异常已经处理,组件也不会记录异常。比如:protected override void OnException(ExceptionContext filterContext) { //如果加了这一句,表示异常已经处理,不会尽到应用程序的Error事件里面去 filterContext.ExceptionHandled = true; //........ base.OnException(filterContext); }
这就是异常捕获器统一处理异常,既然这里标识了异常已经处理过,那么组件肯定不会再次处理。可是有些情况下,我们需要处理某些自定义异常,而对于系统异常我们还是希望组件能够记录,这种情况下怎么办呢?其实很简单,这里只需要判断一下,如果是自定义异常信息,这里就加上 filterContext.ExceptionHandled = true; 这一句,而对于其他系统异常,则统一加上这一句即可。这里还是做一个简单的演示供需要的园友参考。
public class MyException : Exception { public MyException(string message) : base(message) { } }
满足一定条件则抛出自定义异常
public JsonResult Get() { if (DateTime.Now > Convert.ToDateTime("2016-12-15 10:00:00")) { //如果满足某些条件则抛出异常 throw new MyException("当前时间已过期"); } return Json("OK", JsonRequestBehavior.AllowGet); }
然后再全局异常处理里面
protected override void OnException(ExceptionContext filterContext) { if (filterContext.Exception is MyException) { //如果加了这一句,表示异常已经处理,不会进到应用程序的Error事件里面去 filterContext.ExceptionHandled = true; } base.OnException(filterContext); }
这样就能达到我们系统异常记录,自定义异常不记录的目的了。
回到顶部
3、组件权限问题
关于elmah组件,被人诟病的一个重要原因就是其安全问题,如果控制不好很容易招到他人入侵。大神汤姆大叔有篇文章记录这个,有兴趣可以看看。关于我们/elmah.axd路径,我们肯定是需要做一些限制,不能允许每个人都去查看,下面从以下几个方面来完善。(1)拒绝远程访问
在web.config里面有一个节点配置不允许远程访问。<elmah> <security allowRemoteAccess="false" /> </elmah>
(2)拒绝匿名用户访问
对于没有登录到系统的用户,拒绝访问。这个可以在IIS上面配置,当然,我们在web.config里面也要做相应的配置<location path="log.axd" inheritInChildApplications="false"> <system.web> <authorization> <deny users="?"/> </authorization> </system.web> </location>
(3)指定角色或用户访问
可以在应用程序全局配置文件Global.asax里面的认证事件里面去做判断。protected void Application_AuthenticateRequest(object sender, EventArgs e) { HttpApplication app = (HttpApplication)sender; // 处理日志权限问题 if (Request.Url.ToString().Contains("elmah.axd")) { var user = app.Context.User; if (user == null) { Response.Write("无权限访问"); Response.End(); } var userData = (UserInfo)user; //管理员角色才能查看 if (!userData.UserData.IsAdmin) { Response.Write("无权限访问"); Response.End(); } //或者指定用户才能访问 //if (userData.UserData.UserName!="administrator") //{ // Response.Write("无权限访问"); //Response.End(); //} } }
回到顶部
四、总结
以上总结了组件Elmah组件的使用和一些常见问题的处理。有兴趣的可以看看。欢迎推荐!本文原创出处:http://www.cnblogs.com/landeanfen/
欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利
相关文章推荐
- C#组件系列——又一款日志组件:Elmah的学习和分享
- C#组件系列——又一款Excel处理神器Spire.XLS,你值得拥有
- Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!
- C#组件系列——又一款Excel处理神器Spire.XLS,你值得拥有
- C#组件系列——又一款Excel处理神器Spire.XLS,你值得拥有
- C#组件系列 你值得拥有的一款Excel处理神器Spire.XLS
- 【腾讯Bugly干货分享】微信终端跨平台组件 mars 系列(一) - 高性能日志模块xlog
- C#组件系列——又一款Excel处理神器Spire.XLS,你值得拥有(二)
- C#组件系列——又一款Excel处理神器Spire.XLS,你值得拥有(二)
- 如何从零开始开发一款嵌入式产品(20年的嵌入式经验分享学习,来自STM32神舟系列开发板设计师的总结)
- 【腾讯Bugly干货分享】微信终端跨平台组件 mars 系列(一) - 高性能日志模块xlog
- C# 串口操作系列(1) -- 入门篇,一个标准的,简陋的串口例子。 ——兔子党逍遥原创,转来分享学习
- 如何从零开始开发一款嵌入式产品(20年的嵌入式经验分享学习,来自STM32神舟系列开发板设计师的总结)
- C#学习系列-out与ref的区别
- ios开发学习-弹出视图(Popup View) 效果源码分享--系列教程3
- Cocos2d-x 3.1.1 学习日志9--一“上一下其乐无穷”游戏开发系列一
- 【C#】组件分享:FormDragger窗体拖拽器
- JS组件系列——Bootstrap 树控件使用经验分享
- c# .net获取文件夹下的所有文件(多层递归),并获取区间数据(Jsion,xml等数据)写出到处理文件,学习分享~
- C#温故而知新学习系列之.NET运行机制—3-.NET中托管代码是指什么?