C# 全局异常捕获(转载)
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# 全局异常捕获(转载)的更多相关文章
- atitit.js浏览器环境下的全局异常捕获
atitit.js浏览器环境下的全局异常捕获 window.onerror = function(errorMessage, scriptURI, lineNumber) { var s= JSON. ...
- MVC 好记星不如烂笔头之 ---> 全局异常捕获以及ACTION捕获
public class BaseController : Controller { /// <summary> /// Called after the action method is ...
- C#中的那些全局异常捕获
1.WPF全局捕获异常 public partial class App : Application { public App() { // 在异 ...
- Spring-MVC开发之全局异常捕获全面解读
异常,异常 我们一定要捕获一切该死的异常,宁可错杀一千也不能放过一个! 产品上线后的异常更要命,一定要屏蔽错误内容,以免暴露敏感信息! 在用Spring MVC开发WEB应用时捕获全局异常的方法基本有 ...
- Asp.Net MVC3(三)-MvcApp实现全局异常捕获
定义异常捕获类: [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMu ...
- 使用spring利用HandlerExceptionResolver实现全局异常捕获
最近一直没有时间更新是因为一直在更新自己使用的框架. 之后会慢慢带来对之前使用的spring+mvc+mybatis的优化. 会使用一些新的特性,实现一些新的功能. 我会尽量分离业务,封装好再拿出来. ...
- .Net下的全局异常捕获问题
全局异常捕获主要目标并不是为了将异常处理掉防止程序崩溃.因为当错误被你的全局异常捕获器抓到的时候,已经证实了你程序中存在BUG. 一般而言,我们的全局异常捕获主要作用就是接收到异常之后进行异常的反馈. ...
- (转)C#中的那些全局异常捕获
C#中的那些全局异常捕获(原文链接:http://www.cnblogs.com/taomylife/p/4528179.html) 1.WPF全局捕获异常 public partia ...
- springboot(二 如何访问静态资源和使用模板引擎,以及 全局异常捕获)
在我们开发Web应用的时候,需要引用大量的js.css.图片等静态资源. 默认配置 Spring Boot默认提供静态资源目录位置需置于classpath下,目录名需符合如下规则: /static / ...
- spring boot: GlobalDefaultExceptionHandler方法内的友好错误提示,全局异常捕获
spring boot: GlobalDefaultExceptionHandler方法内的友好错误提示,全局异常捕获 当你的某个控制器内的某个方法报错,基本上回显示出java错误代码,非常不友好,这 ...
随机推荐
- opengauss Need repair修复
问题描述:opengauss集群在做切换的时候,或者增删节点的时候,很容易发生节点repair,找不到主库的情况,这种情况需要把主库使用primary角色启动,然后build重建从库,就可以恢复集群 ...
- 动手学Avalonia:基于SemanticKernel与硅基流动构建AI聊天与翻译工具
Avalonia是什么? Avalonia是一个跨平台的UI框架,专为.NET开发打造,提供灵活的样式系统,支持Windows.macOS.Linux.iOS.Android及WebAssembly等 ...
- c语言生成随机数
记录示例,留作自用 #include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) ...
- Mac Vue-cli脚手架搭建
安装node环境 官网地址:http://nodejs.cn/download/ 我选择版本:v16.16.0 修改npm镜像地址 # 查看镜像地址 npm config get registry # ...
- 洛谷P1747
这个题被坑麻了,题目居然不给棋盘的范围,评论区居然有人说棋盘是无限大的,我想说的是如果真是这样那么第9个点答案应该是2而不是3,这个棋盘绝对是有大小的. #include<iostream> ...
- 基于django(爱抚宠物) 小程序设计和实现(源码+LW+部署讲解)
感兴趣的可以先收藏起来,大家在毕设选题,项目以及论文编写等相关问题都可以给我加好友咨询 系统介绍: 科技进步的飞速发展引起人们日常生活的巨大变化,电子信息技术的飞速发展使得电子信息技术的各个领域的应用 ...
- [oeasy]python0127_中文系统_gbk_BIG5_南极星_内码转化
中文系统bgk 回忆上次内容 汉字字形通过 点阵式打字机 像素级寻址的屏幕 进入了计算机的世界 添加图片注释,不超过 140 字(可选) 在海峡对岸的台湾同胞 也进入了汉字时代 他 ...
- oeasy教您玩转vim - 77 - # 保留环境viminfo
保留环境viminfo 回忆组合键映射的细节 上次我们定义了session :mks 还可以加载会话session :source Session.vim vim -S Session.vim 基 ...
- 题解:CF1984B Large Addition
题解:CF1984B Large Addition 题意 判断 \(n\) 是否是两个位数相同的 \(large\) 数的和. 思路 有以下三种证明方法: 最高位为 \(1\),因为两个 \(larg ...
- 【译】宣布三项新的高级 Visual Studio 订阅者福利
Visual Studio 订阅(无论是专业版还是企业版)提供的不仅仅是软件使用权:这是一个全面的工具包,旨在显著提高您的开发能力和职业发展.这些订阅每年可以为您节省数千美元,提供各种服务,从每月用于 ...