你的位置:首页 > ASP.net教程

[ASP.net教程]关于面向切面编程的部分内容


错误处理机制。

面对多个web服务器,多线程处理,我们想把错误信息记录到一个txt文档中。

但是把错误信息写到内存是很快。写到硬盘上就有一堆的问题。比如说读写慢、并发问题。

今天我们就利用这个实现错误处理 此文以MVC为例

1、首先要在  golable  文件的  protected void Application_Start()


注册一个错误处理机制。

MVC中自带一个  过滤器

FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);

image

这里面 我们看到这个过滤器

 

2、其实就是在 app_Start文件夹下面 的 FilterConfig.cs 文件

image

3、 打开FilterConfig.cs文件

就写了一个注册事件。我们看得到 这个是对错误处理机制

image

(当然 ,你们看到的是  HandleErrorAttribute 这个类)

4、所以你们可能觉得奇怪,我们来查看MyExceptionAttribut的定义看一下

image

继承了HandleErrorAttribute

这里我把这个类的代码贴一下


public class MyExceptionAttribute : HandleErrorAttribute
    {
        //  private static object obj = new object();
        public static ConcurrentQueue<Exception> ExceptionQueue = new ConcurrentQueue<Exception>();//定义队列

        /// <summary>
        /// 在该方法中捕获异常。
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnException(ExceptionContext filterContext)
        {

            base.OnException(filterContext);
            Exception ex = filterContext.Exception;//捕获异常信息。
            //将异常信息写到队列中。
            ExceptionQueue.Enqueue(ex);
            //跳转到错误页面.
            filterContext.HttpContext.Response.Redirect("/Error.html");

          

        }
    }

 

主要是定义一个静态 队列  ConcurrentQueue

(当然你也可以用 Queue。但是微软说 这个ConcurrentQueue 比 Queue  安全。好像是线程安全的,一堆堆的理论,说白了就是用ConcurrentQueue 更安全)

这样所有的错误就都在这个队列里面了。(就是内存)

这样总不行吧。内存 断电就没有了的啊。

所以我们要想把资料存到 硬盘中。

5、现在又要在

  golable  文件的  protected void Application_Start()


中注册一个消费线程(这句话后面会解释,看不懂就继续)就是在 protected void Application_Start()中加入这些代码,最好放最前面。

内容就是线程池开启一个线程 从刚刚定义的 MyExceptionAttribute的 ExceptionQueue队列里面取出项来。

将错误信息最加到文件后面。如果队列为空,就线程停留3秒。


string filePath = Server.MapPath("/Log/");
            ThreadPool.QueueUserWorkItem((a) =>
            {

                while (true)//注意:线程不能结束。后面写到队列中的数据没法处理。
                {

    // 这里可以加一条   if (MyExceptionAttribute.ExceptionQueue.Count() > 0)
//{  发送邮件到管理员}
                    if (MyExceptionAttribute.ExceptionQueue.Count() > 0)
                    {
                        // Exception ex= MyExceptionAttribute.ExceptionQueue.Dequeue();//从队列中取出数据.
                        Exception ex = null;
                        bool isResult = MyExceptionAttribute.ExceptionQueue.TryDequeue(out ex);
                        if (ex != null && isResult)
                        {
                            string fullPath = filePath + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
                            File.AppendAllText(fullPath, ex.ToString());
                         //   ILog logger = LogManager.GetLogger("errorMsg");
                          //  logger.Error(ex.ToString());
                        }
                        else
                        {
                            Thread.Sleep(3000);
                        }
                    }
                    else
                    {
                        Thread.Sleep(3000);//避免造成CPU的空转。
                    }
                }

 

            }, filePath);

6、总结。

这个就是一个生产者消费者的模式。

生产者就是 产生错误的源头。 消费者就是注册保存日志的方法。

中间有一个仓库就是    那个静态错误队列。

可以看到 系统产生的错误临时存放于内存中。然后一个新的线程 去读写静态错误队列。

正常情况 需要在错误队列里面加一个错误队列数字大于1000条的时候  发警告到邮箱的功能。那样感觉有点问题复杂化了,毕竟这里只是讲错误处理。

7、log4net 我前面讲过的一个开源框架 记录错误很好。

这里提供一个连接    log4net配置方法你可以把那个一起并到这里。那么就会有

把protected void Application_Start()中添加 的代码

改成。注意是改成:

log4net.Config.            //开始一个线程,查看异常队列
            string filePath = Server.MapPath("/Log/");
            ThreadPool.QueueUserWorkItem((a) =>
            {

                while (true)//注意:线程不能结束。后面写到队列中的数据没法处理。
                {
                    if (MyExceptionAttribute.ExceptionQueue.Count() > 0)
                    {
                        // Exception ex= MyExceptionAttribute.ExceptionQueue.Dequeue();//从队列中取出数据.
                        Exception ex = null;
                        bool isResult = MyExceptionAttribute.ExceptionQueue.TryDequeue(out ex);
                        if (ex != null && isResult)
                        {
                            string fullPath = filePath + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
                            //File.AppendAllText(fullPath, ex.ToString());
                            ILog logger = LogManager.GetLogger("errorMsg");
                            logger.Error(ex.ToString());
                        }
                        else
                        {
                            Thread.Sleep(3000);
                        }
                    }
                    else
                    {
                        Thread.Sleep(3000);//避免造成CPU的空转。
                    }
                }

 

            }, filePath);

这样就会按照你的要求把错误日志记录到

app_data文件夹下面。(前提是你有未处理的错误 。呵呵)

看到下图就成功了

image

题外话(

没有就自己创一个   var s=3/0;

这样就可以了。