首页 > 编程语言 >C#程序全局异常处理—WPF和Web API两种模式

C#程序全局异常处理—WPF和Web API两种模式

时间:2024-02-27 13:34:53浏览次数:21  
标签:Web 自定义 C# System AppExceptionFilterAttribute 处理 API using 异常

C#程序的全局异常处理,网上搜下资料都是一大堆,我这里最近也是独立做一个B/S结构的小项目, 后面又增加了需求用WPF实现相同的功能,这里将我所使用的全局异常处理方式做一个简短的总结分享。
Web API项目的全局异常处理
这种项目下,我们可以直接自定义一个全局异常的过滤器,用来处理全局异常。具体步骤就是在WEB API项目中,定义一个继承自AppExceptionFilterAttribute的类,这个类需要引入命名空间Microsoft.AspNetCore.Mvc.Core.dll,一般来说如果是WEB API或者说MVC的项目,这个会自动帮我们引入或者说VS智能提示帮助我们引入。我们自定义的类只需要重写OnException方法即可,当然现在都推荐使用其异步模式OnExceptionAsync方法,我这里自定义的异常处理类是AppExceptionFilterAttribute,具体代码如下。

自定义的全局异常处理类AppExceptionFilterAttribute
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Abstractions;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WebApi
{
    [AttributeUsage(AttributeTargets.Method|AttributeTargets.Class,AllowMultiple =false,Inherited =false)]
    public class AppExceptionFilterAttribute:ExceptionFilterAttribute
    {
        //private static ILog log = LogManager.GetLogger(typeof(AppExceptionFilter));//typeof放当前类
        public override void OnException(ExceptionContext actionExecutedContext)
        {
            ActionDescriptor actionDescriptor = actionExecutedContext.ActionDescriptor;
            if (actionDescriptor.EndpointMetadata.Any(m => m.GetType() == typeof(SkipFilterAttribute)))
            {
                //判断如果操作方法有SkipFilterAttribute特性,则跳过自定义的过滤器的执行
                base.OnException(actionExecutedContext);
                return;
            }

            Exception ex = actionExecutedContext.Exception;
            if (ex != null)
            {
                string ControllerName = actionDescriptor.RouteValues["controller"];
                string ActionName = actionDescriptor.RouteValues["action"];
                //log.Error(string.Format("Filter捕获到未处理异常:ControllerName={0},ActionName={1}, ExType={2},Source={3},Message={4},Exception={5}", ControllerName, ActionName, ex.GetType(), ex.Source, ex.Message, ex.ToString()));

                JsonResult jsonResult = new JsonResult($"全局Filter已进行错误处理。{ex.Message}");
                jsonResult.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;

                actionExecutedContext.Result = jsonResult;
            }
            actionExecutedContext.ExceptionHandled = true;
        }
    }
}

在上述代码中,只需要将AppExceptionFilterAttribute标记在方法的头上或者Controller的头上即可,如果在方法头上,当程序执行到此方法出现未处理异常时,会由AppExceptionFilterAttribute来处理。我们可以在AppExceptionFilterAttribute中集成日志组件,将错误的异常日记记录下来。如果在Controller的头上标记此特性,那么针对此Controller中定义的方法,在出现异常时都会进入到AppExceptionFilterAttribute来处理。如果想让某个方法不去使用此异常过滤器来处理。我们还可以加上一个跳过的处理操作,上面的代码中SkipFilterAttribute类就是用来做跳过自定义异常处理的功能,只需要定义个空的特性处理类即可,代码如下:

跳过自定义异常处理的特性类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WebApi
{
    /// <summary>
    /// 跳过过滤器的操作,定义在方法头上,带有此标记的方法不会去处理过滤
    /// </summary>
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
    public class SkipFilterAttribute : Attribute
    {

    }
}

最后贴上一段在Controller中使用的代码示例,这个示例中我是在Controller的头上使用了特性类AppExceptionFilterAttribute,而在接口方法Get3DModelData的头上使用了SkipFilterAttribute特性做标记,因此Get3DModelData出现异常后进入AppExceptionFilterAttribute中检测到方法头上标记了SkipFilterAttribute,会跳过自定义异常处理。

Controller中使用自定义异常处理
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace WebApi.Controllers
{
    [AppExceptionFilter]
    [Route("[controller]/[action]")]
    [ApiController]
    public class Dicom3DController : Controller
    {
        [SkipFilterAttribute]
        [HttpPost]
        public IActionResult Get3DModelData([FromBody]Dicom3DRequest request)
        {
            Dicom3DServer server = new Dicom3DServer();
            D3Model model= server.Get3DData(request.StudyId, request.SeireisId,request.CurrentBatch);
            
            return Json(model);
        }

        public IActionResult GetUserInfo()
        {
            return Json("success");
        }
    }
}

WPF全局异常处理
WPF程序的全局异常处理就更简单了,我们创建的WPF的项目入口类都是继承自System.Windows.Application类,默认创建的项目的入口类名为APP,我们在这个类中定义一个构造函数,在其中绑定三个异常事件即可,具体为什么需要三个,直接可以看我代码的注释即可。

WPF的全局异常处理
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApp1
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        public App()
        {
            //当应用程序引发但未处理异常时出现,UI线程的异常,无法捕获多线程异常
            Application.Current.DispatcherUnhandledException += Current_DispatcherUnhandledException;

            //当某个异常未被捕获时出现,Thread多线程和UI线程都可以捕获
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

            //未被观察到的Task多线程异常
            TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
        }

        private void Current_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
        {
            e.Handled = true; //使用e.Handled能防止程序崩溃
            MessageBox.Show($"Current_DispatcherUnhandledException:" + e.Exception.Message);
        }
        private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            MessageBox.Show($"CurrentDomain_UnhandledException:" + (e.ExceptionObject as Exception).Message);
        }
        private void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
        {
            MessageBox.Show($"TaskScheduler_UnobservedTaskException:" + e.Exception.Message);
        }

    }
}

标签:Web,自定义,C#,System,AppExceptionFilterAttribute,处理,API,using,异常
From: https://www.cnblogs.com/huangqian/p/18036541

相关文章

  • Angr Execution Pipeline
    ReferenceUnderstandingtheExecutionPipelineIfyou’vemadeitthisfaryouknowthatatitscore,angrisahighlyflexibleandintenselyinstrumentableemulator.Inordertogetthemostmileageoutofit,you’llwanttoknowwhathappensateveryste......
  • Git出现游离分支(HEAD detached from XXXX解决方法)
    1.检出到该提交使用gitreflog查看Git操作历史:如果想要操作这个特定的提交,可以直接检出:gitcheckout16c80e5这将把HEAD指向这个特定的提交,再次进入一个游离HEAD状态。2.创建一个新分支来保存这个提交在这个游离HEAD状态下,创建一个新分支:gitbranchdev-test-16c80e......
  • Docker环境安装细步骤
    如果之前已有安装有docker需要重新安装,先进行卸载,如果没安装忽略此步骤yumremovedockerdocker-clientdocker-client-latestdocker-commondocker-latestdocker-latest-logrotatedocker-logrotatedocker-engine安装Docker服务安装yum-utils安装所需的依赖组件软件包,执......
  • Taurus.MVC WebMVC 入门开发教程3:数据绑定Model
    前言:在这篇Taurus.MVCWebMVC入门开发教程的第三篇文章中,我们将重点介绍如何进行数据绑定操作,还会学习如何使用${属性名称} CMS语法来绑定页面上的元素与Model中的属性。步骤1:创建Model首先,我们需要创建一个Model类来存储数据。在VisualStudio中,右键单击项目文......
  • Rancher 无法删除集群的Solution
    Rancher无法删除集群的Solution不同版本的Rancher都能遇到该问题,此问题中,Rancher版本为v2.6.0当我们先删除节点,并在节点宿主机上删除了对应的服务器,再通过Rancher界面去删除托管/自建立集群时,往往这个操作会卡住,并出现报错:{"type":"error","links":{},"code":"PermissionDe......
  • 844. 比较含退格的字符串C
    这题学到了很多。malloc后要初始化。申请字符串要N+1个单位字符串以0结尾等等char*final(char*s,intn){char*tem=(char*)malloc(sizeof(char)*(n+1));for(inti=0;i<=n;i++){tem[i]=0;}intj=0;for(inti=0;i<n;i++){if(s[......
  • 13.分布式事件总线DotNetCore.CAP的简单使用
    DotNetCore.CAP框架提供了一个简单易用的API和多种消息传输协议支持(包括Redis、RabbitMQ等),可以让用户轻松地实现消息队列、事件发布/订阅、分布式事务等功能。它还具备自动重试、异常处理、数据序列化等高级特性,可以保证消息的可靠性和一致性。使用DotNetCore.CAP框架,你可以:1.......
  • VSCode+Vim 开发
    VSCode+Vim开发一、安装及配置vim插件0.安装vim拓展1.拷贝配置到settings.json中settings.json在"文件"->"首选项"->"设置"->"文本编辑器"{"vim.easymotion":true,"vim.incsearch":true,"vim.useSystemCl......
  • Office 365 官方原版镜像下载
    中文说明:专业增强版-简体中文版文件名称:O365ProPlusRetail.img下载地址:https://officecdn.microsoft.com/db/492350F6-3A01-4F97-B9C0-C7C6DDF67D60/media/zh-CN/O365ProPlusRetail.img中文说明:专业增强版-繁体中文版文件名称:O365ProPlusRetail.img下载地址:https://officecdn.micr......
  • 《安富莱嵌入式周报》第333期:F35战斗机软件使用编程语言占比,开源10V基准电源,不断电运
    周报汇总地址:http://www.armbbs.cn/forum.php?mod=forumdisplay&fid=12&filter=typeid&typeid=104 视频版:https://www.bilibili.com/video/BV1y1421f7ip目录:1、F35战斗机软件使用编程语言占比2、开源10V基准电源,不断电运行一年,误差小于1uV3、资讯(1)苹果开源配置语言Pkl......