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. 海思SDK 学习 :002-实例代码分析

    背景 需要了解 海思HI35xx平台软件开发快速入门之背景知识,为了方便测试,还需要了解 海思SDK 的安装 知识 由于海思的应用程序启动 MPP 业务前,必须完成 MPP 系统初始化工作.同理,应用 ...

  2. 羊城杯决赛Misc

    羊城杯决赛Misc easy00aes比赛时没离线0宽环境摆了 LmqHmAsk没思路,赛后看着群里各位师傅讨论才明白预期解,wp里直接放toto师傅的脚本了 这里放个toto师傅博客: https: ...

  3. Vite5+Electron聊天室|electron31跨平台仿微信EXE客户端|vue3聊天程序

    基于electron31+vite5+pinia2跨端仿微信Exe聊天应用ViteElectronChat. electron31-vite5-chat原创研发vite5+electron31+pin ...

  4. Python 利用argparse模块实现脚本命令行参数解析

    利用argparse模块实现脚本命令行参数解析 By:授客 QQ:1033553122 #代码实践1 study.py内容如下 #!/usr/bin/env python # -*- coding:u ...

  5. NameCheap域名怎么样,如何注册购买域名?如何解析域名?

    Namecheap介绍 Namecheap是一家国外域名注册商和网站托管公司,成立于2000年,提供域名注册.虚拟主机.电子邮件托管.SSL证书.免费的WHOIS保护.CDN.VPS主机和独立服务器. ...

  6. Scrapy模块入门与实战:笔趣阁小说网爬取

    scrapy框架基本使用 创建项目(爬取笔趣阁小说网) scrapy startproject novels 创建spider cd novels scrapy genspider bqgui.cc ...

  7. windows10使用scp命令

    windows10使用scp命令 windows自带scp命令 windows上传文件到linux//使用方法:scp 源文件路径 账户@地址:目的路径scp   C:\Users\zbh\Deskt ...

  8. vue3源码学习api-vue-sfc文件编译

    vue 最有代表性质的就是.VUE 的文件,每一个vue文件都是一个组件,那么vue 组件的编译过程是什么样的呢 Vue 单文件组件 (SFC)和指令 ast 语法树 一个 Vue 单文件组件 (SF ...

  9. 【Java】CompletableFuture 异步任务编排

    参考视频资料: https://www.bilibili.com/video/BV1nA411g7d2 https://www.bilibili.com/video/BV1S54y1u79K 一.启动 ...

  10. 【Layui】15 日期时间选择器 Laydate

    文档地址: https://www.layui.com/demo/laydate.html [基本案例] 基本日期与国际日期 <fieldset class="layui-elem-f ...