C# 全局异常捕获

原文地址:https://www.cnblogs.com/tomahawk/articles/5993874.html

开发界有那么一个笑话,说是“「我爱你」三个字,讲出来只要三秒钟,解释要三小时,证明却要一辈子。「Bug」三个字母,发现需要三秒,找到需要三小时,Debug却要一辈子。”。就算是资深的程序员也会写出Bug,但Bug并不可怕,重要的是在Bug发生的时候迅速定位Bug。

在Visual Studio中调试的时候,我们可以借助VS的调试工具进行调试,一旦出现未处理的异常时,VS也会在第一时间捕获并显示出来。随着开发的进行,终于程序要打包上线了。那么在上线之出了BUG我们该如何处理呢?

相信如果各位年龄够大,应该都见识过QQ出错崩溃吧?在零几年的时候QQ崩溃还不是一件稀罕事儿。每当QQ崩溃的时候都会弹出一个BUGReporter程序,会希望我们将出错的报告发送给腾讯

其实我们标题所说的全局异常捕获主要目标并不是为了将异常处理掉防止程序崩溃。因为当错误被你的全局异常捕获器抓到的时候,已经证实了你程序中存在BUG。一般而言,我们的全局异常捕获主要作用就是接收到异常之后进行异常的反馈。

一、简单粗暴:在Program.cs使用Try...Catch...

大家都知道,异常是通过Throw命令抛出,一路从抛出的模块里上抛,如果中途没有被try...catch...抓住的话就会一直抛到CLR(公共语言运行时)。如果用栈来描述这个过程的话,那就是异常会从栈的栈顶一路下沉,直到中途被try...catch...抓住或者直至沉到栈底,被CLR接住。CLR接收到异常之后的处理方式非常的简单粗暴——直接报错,然后关闭程序。大概表现就是这样:

这样:

还有这样:

不过根据刚刚我们所描述的异常上抛过程,我们不难发现:只要我们在程序把异常抛给CLR之前,抢先把异常捕获,那就可以做到全局异常处理了。不过这个try...catch...就必须放在栈的最下方。程序运行时栈的最下方函数其实就是程序运行时第一个调用的函数——main()函数。

比如说我有这么一个Windows窗体程序,一个Program.cs类,一个FrmMain.cs窗口。

Program.cs类内容如下:

static class Program
{
    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new FrmMain());
    }
}

FrmMain里有一个Button,其点击事件如下:

private void button1_Click(object sender, EventArgs e)
{
    throw new Exception();
}

如果就现在这样的代码而言,只要在运行时单击这个Button就能时整个程序报错崩溃。

现在我们改造Program.cs里的main()函数,改成以下内容:

/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
    try
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new FrmMain());
    }
    catch (Exception ex)
    {
        MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}", ex.GetType(), ex.Message, ex.StackTrace));
    }
}

现在再次执行程序,单击button1,我们可以看到现在这次的这个异常被main()函数中的try...catch...所抓获了。

我们在这里catch内只是放了一个MessageBox,后面可以根据自己的需要改成错误报告代码。

二、更优雅的事件监听:Application.ThreadException

刚刚在上面提到了一种简单粗暴的方法,就是用try...catch...把main()函数所有内容全部包住。不过这样的代码看起来就有点蠢了。有没有什么更加优雅的方法吗?

答案当然是有。还记得Application类吧,这个负责控制整个Windows 程序的运行。我们可能用到这个类的时候更多的时候用的是下面几个方法或属性:

今天在这里我们要用到一个Application类的一个事件:ThreadException。

我们可以按F12转到Application类的定义,在ThreadException事件上,微软对它的注释是:“在发生未捕获线程异常时发生。”,这正是我们的目标。

假设还是之前的那个程序,我们将程序的Program.cs内容填入以下代码:

static class Program
{
    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.ThreadException += Application_ThreadException;
         
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new FrmMain());
    }
 
    static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
    {
        Exception ex = e.Exception;
        MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}", ex.GetType(), ex.Message, ex.StackTrace));
    }
}

现在我们重新运行这个程序,单击button1,查看效果:

可以说效果出乎意料的完美,上一章里在main()函数里用try..catch...包住所有代码,当程序异常时将代码将会进入catch块里,处理完成后程序就退出了。然而在这边我们用Application.ThreadException事件监听并处理后,程序并不会因为异常而退出。可以说是可挽回的异常。

三、子线程异常捕获AppDomain.CurrentDomain.UnhandledException

在上面我们提到了可以通过监听Application.ThreadException事件来捕获程序异常,但这个Application.ThreadException事件只能捕获程序主线程上发生的异常。如果你用到了多线程,而且在子线程中发生了异常,不会触发Application.ThreadException事件的。

如果要监听子线程的异常,我们就需要再注册一个事件:AppDomain.CurrentDomain.UnhandledException

这个事件是在当前程序域内发生未处理异常时才会发生(如果没有监听Application.ThreadException事件的话,主线程异常最终也会触发这个事件)

我们在第一章的窗口里再加一个Button按钮,名为button2,其单击事件内容为:

private void button2_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(() =>
    {
        throw new Exception();
    });
    thread.Start();
}

上面的代码会在运行时创建一个线程,线程代码只有一句“throw new Exception();”致使线程抛出异常。

我们再改一下Program.cs类的内容:

static class Program
{
    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.ThreadException += Application_ThreadException;
        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
         
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new FrmMain());
    }
     
    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Exception ex = e.ExceptionObject as Exception;
        MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}\r\nCLR即将退出:{3}", ex.GetType(), ex.Message, ex.StackTrace, e.IsTerminating));
    }
     
    static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
    {
        Exception ex = e.Exception;
        MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}", ex.GetType(), ex.Message, ex.StackTrace));
    }
}

我们来试一下,运行程序,单击button2:

漂亮,监听到事件了。但在这里我们需要注意的是注意这个AppDomain.CurrentDomain.UnhandledException事件有一个事件参数叫UnhandledExceptionEventArgs e,它有一个bool类型的IsTerminating属性。这个属性指示了公共语言运行时(CLR)会不会因为本次异常而退出。如果这个属性是true的话,那么我们可以称这个错误是不可挽回的,就算我们监听到了这个事件,在这个事件的代码执行结束后,整个程序还是会崩溃退出的(因为我在VS里,所以被VS捕捉到了。)。

四、Web程序全局异常捕获

之前提到的都是Windows程序的全局异常捕获,现在Web程序也是我们经常要与之打交道的一部分。那Web程序该如何进行全局异常捕获呢?,下面以Asp.net MVC4做演示。

我们假设我们有一个Home控制器(Controller),里面有一个Error页面,访问这个页面将抛出一个异常。

public class HomeController : Controller
{
    public ActionResult Error()
    {
        throw new Exception();
    }
}

1. Global.asax中编写Application_Error函数

我们可以在Global.asax里写一个protected void Application_Error(object sender, EventArgs e)的函数,当发生未经处理的异常时,Asp.net将自动执行此函数。

在Global.asax文件的MvcApplication类里其他空白位置写上以下代码:

protected void Application_Error(object sender, EventArgs e)
{
    //获取到HttpUnhandledException异常,这个异常包含一个实际出现的异常
    Exception ex = Server.GetLastError();
    //实际发生的异常
    Exception innerException = ex.InnerException;
    if (innerException != null) ex = innerException;
     
    using (StreamWriter sw = new StreamWriter(@"C:\Log.txt"true))
    {
        sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
        sw.WriteLine("Global捕获到未处理异常:" + ex.GetType().ToString());
        sw.WriteLine("异常信息:" + ex.Message);
        sw.WriteLine("异常堆栈:" + ex.StackTrace);
        sw.WriteLine();
    }
     
    HttpContext.Current.Response.Write(string.Format("捕捉到未处理的异常:{0}<br/>", ex.GetType().ToString()));
    HttpContext.Current.Response.Write("Global已进行错误处理。");
     
    Server.ClearError();
}

实际运行情况:

2.使用Filter进行全局异常捕获

Filter其实就是过滤器,在Asp.net MVC中Filter一共分为4大类

分类 接口 默认实现 运行时间
Authorization IAuthorizationFilter AuthorizeAttribute 在Action方法之前和其它类型的Filter之前运行。
Action IActionFilter ActionFilterAttribute 在Action方法之前运行。
Result IResultFilter ActionFilterAttribute 在处理ActionResult之前或之后运行。
Exception IExceptionFilter HandleErrorAttribute 在Action方法、ActionResult和其他类型的Filter抛出异常时运行。

我们可以看到有一个Exception类型的Filter,我们在这里就是借助这个Exception的Filter进行全局异常捕获。

新建一个类,名叫MyExceptionFilter,使其继承FilterAttribute类,并实现IexceptionFilter接口。MyExceptionHandler类代码如下:

using System;
using System.IO;
using System.Web.Mvc;
 
namespace MvcApplication2
{
    public class MyExceptionHandler : FilterAttribute, IExceptionFilter
    {
        public void OnException(ExceptionContext filterContext)
        {
            Exception ex = filterContext.Exception as Exception;
            if (ex != null)
            {
                filterContext.Controller.ViewBag.UrlRefer = filterContext.HttpContext.Request.UrlReferrer;
                 
                using (StreamWriter sw = new StreamWriter(@"C:\Log.txt"true))
                {
                    sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                    sw.WriteLine("Filter捕获到未处理异常:" + ex.GetType().ToString());
                    sw.WriteLine("异常信息:" + ex.Message);
                    sw.WriteLine("异常堆栈:" + ex.StackTrace);
                    sw.WriteLine();
                }
         
                filterContext.HttpContext.Response.Write(string.Format("捕捉到未处理的异常:{0}<br/>", ex.GetType().ToString()));
                filterContext.HttpContext.Response.Write("Filter已进行错误处理。");
            }
 
            filterContext.ExceptionHandled = true;//设置异常已经处理
        }
    }
}

然后我们打开项目的“App_Start”文件夹下的“FilterConfig.cs”文件,修改其RegisterGlobalFilters方法内的代码,修改如下:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new MyExceptionHandler(), 1);//自定义的验证特性
    filters.Add(new HandleErrorAttribute(), 2);
}

启动Web程序查看效果:

C# 全局异常捕获

开发界有那么一个笑话,说是“「我爱你」三个字,讲出来只要三秒钟,解释要三小时,证明却要一辈子。「Bug」三个字母,发现需要三秒,找到需要三小时,Debug却要一辈子。”。就算是资深的程序员也会写出Bug,但Bug并不可怕,重要的是在Bug发生的时候迅速定位Bug。

在Visual Studio中调试的时候,我们可以借助VS的调试工具进行调试,一旦出现未处理的异常时,VS也会在第一时间捕获并显示出来。随着开发的进行,终于程序要打包上线了。那么在上线之出了BUG我们该如何处理呢?

相信如果各位年龄够大,应该都见识过QQ出错崩溃吧?在零几年的时候QQ崩溃还不是一件稀罕事儿。每当QQ崩溃的时候都会弹出一个BUGReporter程序,会希望我们将出错的报告发送给腾讯

其实我们标题所说的全局异常捕获主要目标并不是为了将异常处理掉防止程序崩溃。因为当错误被你的全局异常捕获器抓到的时候,已经证实了你程序中存在BUG。一般而言,我们的全局异常捕获主要作用就是接收到异常之后进行异常的反馈。

一、简单粗暴:在Program.cs使用Try...Catch...

大家都知道,异常是通过Throw命令抛出,一路从抛出的模块里上抛,如果中途没有被try...catch...抓住的话就会一直抛到CLR(公共语言运行时)。如果用栈来描述这个过程的话,那就是异常会从栈的栈顶一路下沉,直到中途被try...catch...抓住或者直至沉到栈底,被CLR接住。CLR接收到异常之后的处理方式非常的简单粗暴——直接报错,然后关闭程序。大概表现就是这样:

这样:

还有这样:

不过根据刚刚我们所描述的异常上抛过程,我们不难发现:只要我们在程序把异常抛给CLR之前,抢先把异常捕获,那就可以做到全局异常处理了。不过这个try...catch...就必须放在栈的最下方。程序运行时栈的最下方函数其实就是程序运行时第一个调用的函数——main()函数。

比如说我有这么一个Windows窗体程序,一个Program.cs类,一个FrmMain.cs窗口。

Program.cs类内容如下:

static class Program
{
    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new FrmMain());
    }
}

FrmMain里有一个Button,其点击事件如下:

private void button1_Click(object sender, EventArgs e)
{
    throw new Exception();
}

如果就现在这样的代码而言,只要在运行时单击这个Button就能时整个程序报错崩溃。

现在我们改造Program.cs里的main()函数,改成以下内容:

/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
    try
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new FrmMain());
    }
    catch (Exception ex)
    {
        MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}", ex.GetType(), ex.Message, ex.StackTrace));
    }
}

现在再次执行程序,单击button1,我们可以看到现在这次的这个异常被main()函数中的try...catch...所抓获了。

我们在这里catch内只是放了一个MessageBox,后面可以根据自己的需要改成错误报告代码。

二、更优雅的事件监听:Application.ThreadException

刚刚在上面提到了一种简单粗暴的方法,就是用try...catch...把main()函数所有内容全部包住。不过这样的代码看起来就有点蠢了。有没有什么更加优雅的方法吗?

答案当然是有。还记得Application类吧,这个负责控制整个Windows 程序的运行。我们可能用到这个类的时候更多的时候用的是下面几个方法或属性:

今天在这里我们要用到一个Application类的一个事件:ThreadException。

我们可以按F12转到Application类的定义,在ThreadException事件上,微软对它的注释是:“在发生未捕获线程异常时发生。”,这正是我们的目标。

假设还是之前的那个程序,我们将程序的Program.cs内容填入以下代码:

static class Program
{
    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.ThreadException += Application_ThreadException;
         
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new FrmMain());
    }
 
    static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
    {
        Exception ex = e.Exception;
        MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}", ex.GetType(), ex.Message, ex.StackTrace));
    }
}

现在我们重新运行这个程序,单击button1,查看效果:

可以说效果出乎意料的完美,上一章里在main()函数里用try..catch...包住所有代码,当程序异常时将代码将会进入catch块里,处理完成后程序就退出了。然而在这边我们用Application.ThreadException事件监听并处理后,程序并不会因为异常而退出。可以说是可挽回的异常。

三、子线程异常捕获AppDomain.CurrentDomain.UnhandledException

在上面我们提到了可以通过监听Application.ThreadException事件来捕获程序异常,但这个Application.ThreadException事件只能捕获程序主线程上发生的异常。如果你用到了多线程,而且在子线程中发生了异常,不会触发Application.ThreadException事件的。

如果要监听子线程的异常,我们就需要再注册一个事件:AppDomain.CurrentDomain.UnhandledException

这个事件是在当前程序域内发生未处理异常时才会发生(如果没有监听Application.ThreadException事件的话,主线程异常最终也会触发这个事件)

我们在第一章的窗口里再加一个Button按钮,名为button2,其单击事件内容为:

private void button2_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(() =>
    {
        throw new Exception();
    });
    thread.Start();
}

上面的代码会在运行时创建一个线程,线程代码只有一句“throw new Exception();”致使线程抛出异常。

我们再改一下Program.cs类的内容:

static class Program
{
    /// <summary>
    /// 应用程序的主入口点。
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.ThreadException += Application_ThreadException;
        AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
         
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new FrmMain());
    }
     
    static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
    {
        Exception ex = e.ExceptionObject as Exception;
        MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}\r\nCLR即将退出:{3}", ex.GetType(), ex.Message, ex.StackTrace, e.IsTerminating));
    }
     
    static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)
    {
        Exception ex = e.Exception;
        MessageBox.Show(string.Format("捕获到未处理异常:{0}\r\n异常信息:{1}\r\n异常堆栈:{2}", ex.GetType(), ex.Message, ex.StackTrace));
    }
}

我们来试一下,运行程序,单击button2:

漂亮,监听到事件了。但在这里我们需要注意的是注意这个AppDomain.CurrentDomain.UnhandledException事件有一个事件参数叫UnhandledExceptionEventArgs e,它有一个bool类型的IsTerminating属性。这个属性指示了公共语言运行时(CLR)会不会因为本次异常而退出。如果这个属性是true的话,那么我们可以称这个错误是不可挽回的,就算我们监听到了这个事件,在这个事件的代码执行结束后,整个程序还是会崩溃退出的(因为我在VS里,所以被VS捕捉到了。)。

四、Web程序全局异常捕获

之前提到的都是Windows程序的全局异常捕获,现在Web程序也是我们经常要与之打交道的一部分。那Web程序该如何进行全局异常捕获呢?,下面以Asp.net MVC4做演示。

我们假设我们有一个Home控制器(Controller),里面有一个Error页面,访问这个页面将抛出一个异常。

public class HomeController : Controller
{
    public ActionResult Error()
    {
        throw new Exception();
    }
}

1. Global.asax中编写Application_Error函数

我们可以在Global.asax里写一个protected void Application_Error(object sender, EventArgs e)的函数,当发生未经处理的异常时,Asp.net将自动执行此函数。

在Global.asax文件的MvcApplication类里其他空白位置写上以下代码:

protected void Application_Error(object sender, EventArgs e)
{
    //获取到HttpUnhandledException异常,这个异常包含一个实际出现的异常
    Exception ex = Server.GetLastError();
    //实际发生的异常
    Exception innerException = ex.InnerException;
    if (innerException != null) ex = innerException;
     
    using (StreamWriter sw = new StreamWriter(@"C:\Log.txt"true))
    {
        sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
        sw.WriteLine("Global捕获到未处理异常:" + ex.GetType().ToString());
        sw.WriteLine("异常信息:" + ex.Message);
        sw.WriteLine("异常堆栈:" + ex.StackTrace);
        sw.WriteLine();
    }
     
    HttpContext.Current.Response.Write(string.Format("捕捉到未处理的异常:{0}<br/>", ex.GetType().ToString()));
    HttpContext.Current.Response.Write("Global已进行错误处理。");
     
    Server.ClearError();
}

实际运行情况:

2.使用Filter进行全局异常捕获

Filter其实就是过滤器,在Asp.net MVC中Filter一共分为4大类

分类 接口 默认实现 运行时间
Authorization IAuthorizationFilter AuthorizeAttribute 在Action方法之前和其它类型的Filter之前运行。
Action IActionFilter ActionFilterAttribute 在Action方法之前运行。
Result IResultFilter ActionFilterAttribute 在处理ActionResult之前或之后运行。
Exception IExceptionFilter HandleErrorAttribute 在Action方法、ActionResult和其他类型的Filter抛出异常时运行。

我们可以看到有一个Exception类型的Filter,我们在这里就是借助这个Exception的Filter进行全局异常捕获。

新建一个类,名叫MyExceptionFilter,使其继承FilterAttribute类,并实现IexceptionFilter接口。MyExceptionHandler类代码如下:

using System;
using System.IO;
using System.Web.Mvc;
 
namespace MvcApplication2
{
    public class MyExceptionHandler : FilterAttribute, IExceptionFilter
    {
        public void OnException(ExceptionContext filterContext)
        {
            Exception ex = filterContext.Exception as Exception;
            if (ex != null)
            {
                filterContext.Controller.ViewBag.UrlRefer = filterContext.HttpContext.Request.UrlReferrer;
                 
                using (StreamWriter sw = new StreamWriter(@"C:\Log.txt"true))
                {
                    sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
                    sw.WriteLine("Filter捕获到未处理异常:" + ex.GetType().ToString());
                    sw.WriteLine("异常信息:" + ex.Message);
                    sw.WriteLine("异常堆栈:" + ex.StackTrace);
                    sw.WriteLine();
                }
         
                filterContext.HttpContext.Response.Write(string.Format("捕捉到未处理的异常:{0}<br/>", ex.GetType().ToString()));
                filterContext.HttpContext.Response.Write("Filter已进行错误处理。");
            }
 
            filterContext.ExceptionHandled = true;//设置异常已经处理
        }
    }
}

然后我们打开项目的“App_Start”文件夹下的“FilterConfig.cs”文件,修改其RegisterGlobalFilters方法内的代码,修改如下:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new MyExceptionHandler(), 1);//自定义的验证特性
    filters.Add(new HandleErrorAttribute(), 2);
}

启动Web程序查看效果:

写在最后:

在Windows程序里,如果同时监听了Application.ThreadException事件和AppDomain.CurrentDomain.UnhandledException事件的话,则异常优先被Application.ThreadException事件捕获。但Application.ThreadException事件只能监听程序主线程抛出的异常。

在Web程序里,如果同时使用了Global.asax中编写Application_Error函数进行全局异常捕获和使用Filter进行全局异常捕获,异常优先被Filter捕获。

C# 全局异常捕获(转载)的更多相关文章

  1. atitit.js浏览器环境下的全局异常捕获

    atitit.js浏览器环境下的全局异常捕获 window.onerror = function(errorMessage, scriptURI, lineNumber) { var s= JSON. ...

  2. MVC 好记星不如烂笔头之 ---> 全局异常捕获以及ACTION捕获

    public class BaseController : Controller { /// <summary> /// Called after the action method is ...

  3. C#中的那些全局异常捕获

    1.WPF全局捕获异常     public partial class App : Application     {         public App()         {    // 在异 ...

  4. Spring-MVC开发之全局异常捕获全面解读

    异常,异常 我们一定要捕获一切该死的异常,宁可错杀一千也不能放过一个! 产品上线后的异常更要命,一定要屏蔽错误内容,以免暴露敏感信息! 在用Spring MVC开发WEB应用时捕获全局异常的方法基本有 ...

  5. Asp.Net MVC3(三)-MvcApp实现全局异常捕获

    定义异常捕获类: [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMu ...

  6. 使用spring利用HandlerExceptionResolver实现全局异常捕获

    最近一直没有时间更新是因为一直在更新自己使用的框架. 之后会慢慢带来对之前使用的spring+mvc+mybatis的优化. 会使用一些新的特性,实现一些新的功能. 我会尽量分离业务,封装好再拿出来. ...

  7. .Net下的全局异常捕获问题

    全局异常捕获主要目标并不是为了将异常处理掉防止程序崩溃.因为当错误被你的全局异常捕获器抓到的时候,已经证实了你程序中存在BUG. 一般而言,我们的全局异常捕获主要作用就是接收到异常之后进行异常的反馈. ...

  8. (转)C#中的那些全局异常捕获

    C#中的那些全局异常捕获(原文链接:http://www.cnblogs.com/taomylife/p/4528179.html)   1.WPF全局捕获异常       public partia ...

  9. springboot(二 如何访问静态资源和使用模板引擎,以及 全局异常捕获)

    在我们开发Web应用的时候,需要引用大量的js.css.图片等静态资源. 默认配置 Spring Boot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则: /static / ...

  10. spring boot: GlobalDefaultExceptionHandler方法内的友好错误提示,全局异常捕获

    spring boot: GlobalDefaultExceptionHandler方法内的友好错误提示,全局异常捕获 当你的某个控制器内的某个方法报错,基本上回显示出java错误代码,非常不友好,这 ...

随机推荐

  1. Elastic-Search 整理(二):高级篇

    ES高级篇 集群部署 集群的意思:就是将多个节点归为一体罢了,这个整体就有一个指定的名字了 window中部署集群 - 了解 把下载好的window版的ES中的data文件夹.logs文件夹下的所有的 ...

  2. ubuntu20 配置nginx静态文件访问

    前言 在ubuntu上配置nginx,通过网页可以直接访问ubuntu本地文件,留作参考. 配置 我的nginx配置文件路径在/etc/nginx/目录下. 查看/etc/nginx/nginx.co ...

  3. SpringBoot集成实时通讯WebSocket和其它代替方案

    WebSocket 双向实时通讯 一.添加WebSocketConfig配置类 /** * 开启WebSocketConfig */ @Configuration public class WebSo ...

  4. Redis缓存雪崩,击穿,穿透以及解决方案

    Redis读写过程 一般情况下,Redis都是作为client与MySQL间的一层缓存,尽量减少MySQL的读压力,数据流向如图所示: Redis的五种数据类型及使用场景 String 这个其实没啥好 ...

  5. 解决方案 | Chrome/Edge 总是自动修改我的pdf默认打开方式

    1.问题描述 最近我的pdf文件总是被chrome打开(如图1),而且点击属性,更改别的pdf阅读器也不管用(如图2),此时的chrome就像个流氓软件一样. 图1 被chrome劫持 图2 点击属性 ...

  6. git将本地代码提交到远程仓库

    来源:https://blog.csdn.net/gaoying_blogs/article/details/53337112 将本地代码上传到远程仓库的时候,打开命令行窗口,进入到本地代码的文件夹. ...

  7. leetcode简单(数组,字符串,链表):[168, 171, 190, 205, 228, 448, 461, 876, 836, 844]

    目录 168. Excel表列名称 171. Excel 表列序号 190. 颠倒二进制位 205. 同构字符串 228. 汇总区间 448. 找到所有数组中消失的数字 461. 汉明距离 876. ...

  8. SQL Server 查询分析及优化方法

    一.影响速度的因素 没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷) I/O吞吐量小,形成了瓶颈效应 没有创建计算列导致查询不优化 内存不足 网络速度慢 查询出的数据量过大(可以采 ...

  9. QT 开发快速入门

    本人 qt 业余,但有的时候要用到 qt,而又没有系统的学习,用到哪里看哪里. 环境: vs2012+ qt-vsaddins+qt5.5 qt 的按钮点击事件出发的基本要素: 1. 按钮触发函数为 ...

  10. 再读vue

    app.vue是项目的主组件,页面的入口文件 main.js是项目的入口文件 vue.config.js是vue-cli的配置文件//用这个配置代理,端口号 例如 const { defineConf ...