65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Entity Framework 和 ASP.NET MVC 自定义 ELMAH 以防止其记录不必要的错误

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (6投票s)

2015 年 12 月 14 日

CPOL

4分钟阅读

viewsIcon

17273

使用 Entity Framework 和 ASP.Net MVC 简介几个月前,我需要在我的一个项目中使用 ELMAH(如果您还没听说过,您可以在这里看到它可以为您做什么),但该组件开箱即用有一些

引言

几个月前,我需要在我的一个项目中使用 ELMAH(如果您还没听说过,您可以在这里看到它可以为您做什么 这里),但该组件开箱即用在我看来有一些问题,例如当发生错误时,ELMAH 会继续记录错误,但是如果您例如连续刷新页面 20 次,ELMAH 将多次记录该错误,我们都知道当用户认为如果他/她刷新页面时,页面可能会起作用,这种情况会发生在应用程序中,因此这可能会导致我们的数据库中出现很多不必要的记录(假设我们已将其连接到数据库),或者当您设置 ELMAH 在发生错误时向您发送电子邮件时,可能会发生另一个潜在问题,这时您可能会遭受很多自找的垃圾邮件,您的收件箱将被与同一错误相关的电子邮件淹没,这可能由于各种原因发生,例如机器人尝试搜索您的网站的特定 URL,例如 WordPress 登录页面,并且该机器人枚举数百个页面以查看您是否拥有它,并且每次 ELMAH 抛出 404 错误时,您将收到一百五十个 404 错误。

在本文中,我将向您展示如何自定义 ELMAH 以避免出现此类问题,当时我在网上搜索此问题的简单解决方案时,我还没有找到一个,因此在本文中,我使用了一些 nugget 包和工具,这些工具使 ELMAH 的使用更加容易,并使用它们来限制 ELMAH 符合我们的喜好。

安装和配置 ELMAH 以将错误记录到数据库并发送电子邮件

在诸如 Elmah.MVC 之类的 nugget 包存在之前,您必须自己添加 ELMAH dll 并设置配置,这些天您所要做的就是添加 Elmah.MVC nugget 包,它会为您处理所有管道工作,如果您还想将错误记录到数据库中,请将包 Elmah.SqlServer.EFInitializer 添加到您的项目中,此包将 ElmahInitializer 类添加到您的项目中,并在该类中设置一个初始化程序以为您创建必要的数据库,您所需要做的就是有一个连接字符串,您可以在 ELMAH xml 部分中指定您的连接字符串


      

如果您还想发送电子邮件,则需要在 web.Config 中设置一个邮件设置部分,ELMAH 将自动拾取它并使用它来发送电子邮件: 


      
        
          
        
      

在 web.Config 的 ELMAH 部分中,您可以使用下面的节点来说明您希望 ELMAH 将记录的错误发送到您的电子邮件


      

限制 ELMAH 发送不必要的电子邮件并将相同的错误记录到数据库中

防止 ELMAH 在发生 404 错误时发送电子邮件

限制 ELMAH 时,您可能要做的第一件事是忽略 404 错误,您每天都会收到大量的 404 错误,如果您要收到每个错误的电子邮件,您的邮箱将会爆炸,您可以通过在 xml 的 ELMAH 部分中添加过滤器来防止 ELMAH 发送此类电子邮件
 


      
 
      
        
          
            
            
          
        
      

您可能还希望将对 ELMAH 的访问限制为具有管理员角色的经过身份验证的用户,您可以通过将此内容添加到 web.Config 的 appSettings 部分来实现


      
      
      
      
      
      
      
      

防止 ELMAH 在刷新时多次记录相同的错误

ELMAH 默认提供一些事件,我们可以使用这些事件来更改其错误记录的工作流程,其中一些事件是 ErrorLog_FilteringErrorMail_Filtering,我们可以在 global.asax 文件中使用这些事件,这是我为限制 ELMAH 仅在错误不是同一错误并且发生时间超过十分钟前才记录错误而想出的方法,此外,我忽略了 HttpRequestValidationExceptionFileNotFoundException 类型的错误,并阻止它们进入数据库或最终进入我的邮箱

        private bool _sendEmail;
        void ErrorLog_Filtering(object sender, ExceptionFilterEventArgs e)
        {
            using (var context = new ElmahContext())
            {
                //if the exception had the same message and was from 
                //the last 10 min it means it's the same we dismiss it
                _sendEmail = true;

                var lastErr = context.ELMAH_Errors
                              .OrderByDescending(m => m.TimeUtc).Take(1)
                              .SingleOrDefault();

                if (lastErr != null &&
                    (e.Exception.Message == lastErr.Message &&
                    lastErr.TimeUtc > DateTime.UtcNow.AddMinutes(-10)))
                {
                    e.Dismiss();
                    _sendEmail = false;
                }
            }

            if (e.Exception.GetBaseException() is HttpRequestValidationException) e.Dismiss();
        }

        void ErrorMail_Filtering(object sender, ExceptionFilterEventArgs e)
        {
            if (_sendEmail == false)
            {
                e.Dismiss();
            }

            if (e.Exception.GetBaseException() is FileNotFoundException) e.Dismiss();
        }

从数据库中删除旧的且不需要的 ELMAH 日志以节省数据库空间

如果要每次记录错误时都执行某些操作,您可以在 ErrorLog_Logged 中执行此操作,在这里我编写了一些代码来检查我的数据库中是否有超过 60 天的错误,如果有,我会将它们删除

void ErrorLog_Logged(object sender, ErrorLoggedEventArgs args)
        {
            //keep the log form the last 60 days and delete the rest
            using (var context = new ElmahContext())
            {
                var baseLineDate = DateTime.UtcNow.AddDays(-60);
                var model = context.ELMAH_Errors.Where(p => p.TimeUtc < baseLineDate);
                foreach (var item in model)
                {
                    context.ELMAH_Errors.Remove(item);
                }
                context.SaveChanges();
            }
        }

这是我自定义 ELMAH 的方法,我相信还有其他方法可以执行我在这里所做的相同操作,如果您有任何问题,请在评论部分告诉我。

© . All rights reserved.