惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Jina AI
Jina AI
大猫的无限游戏
大猫的无限游戏
T
Tailwind CSS Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
WordPress大学
WordPress大学
Last Week in AI
Last Week in AI
Hugging Face - Blog
Hugging Face - Blog
阮一峰的网络日志
阮一峰的网络日志
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
人人都是产品经理
人人都是产品经理
V
V2EX
博客园 - 叶小钗
雷峰网
雷峰网
小众软件
小众软件
量子位
V
Visual Studio Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The GitHub Blog
The GitHub Blog
Martin Fowler
Martin Fowler
G
Google Developers Blog
博客园_首页
博客园 - Franky
有赞技术团队
有赞技术团队
宝玉的分享
宝玉的分享

博客园 - 试试手气

Web Worker 入门 若依Ruoyi分离版替换 MyBatis-Plus 若依前端菜单管理中路由地址、组件路径、权限字符的使用 Idea clone 项目推送到自有仓库 Spring Boot —— Spring Security Spring Boot —— 集成文档工具 Spring Boot —— Filter 过滤器 Spring Boot —— Cors 跨域 Spring Boot —— 集成 Druid Spring Boot —— 集成 MyBatis-Plus Spring Boot —— 集成 Springdoc Navicat 使用笔记 Datagrip连接SQLServer失败 Asp.net Core 笔记 mybatis 笔记 SQLServer 笔记 Asp.net Core 全局异常处理 SqlSugar 实践笔记 Asp.net Core 基于Cookie的身份认证
Asp.net mvc 笔记
试试手气 · 2023-08-23 · via 博客园 - 试试手气

捕捉处理全局异常

  1. 自定义异常处理类如LogErrorAttribute继承HandleErrorAttribute并重写OnException实现处理逻辑
  2. LogErrorAttribute加入启动时的Filter注册使之在管道中生效
  3. 在需要捕捉异常的Controller、Action上使用它

自定义异常处理类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using NLog;
using EmpowerApiService.Entity;
using Newtonsoft.Json;

namespace EmpowerApiService.Filter
{
    public class LogErrorAttribute : HandleErrorAttribute
    {
        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();

        public override void OnException(ExceptionContext filterContext)
        {
            // 如果发现被处理过,则不进行处理
            if (filterContext.ExceptionHandled) { return; }

            // 可获取一些关键参数待用
            var controllerName = (string)filterContext.RouteData.Values["controller"];
            var actionName = (string)filterContext.RouteData.Values["action"];

            // 将http上下文关键信息写入日志
            if (filterContext.HttpContext != null && filterContext.HttpContext.Request != null)
            {
                var requestUrl = filterContext.HttpContext.Request.Url.ToString();
                var requestParams = filterContext.HttpContext.Request.Params;
                var requestParamsStr = HttpUtility.UrlDecode(requestParams.ToString());

                // 写日志
                logger.Error(
                    filterContext.Exception,
                    "url: {0}, params: {1}",
                    new Object[] { requestUrl, requestParamsStr });
            }

            // build http response result
            filterContext.Result = new JsonResult
            {
                ContentType = "applicaltion/json",
                ContentEncoding = System.Text.Encoding.UTF8,
                Data = BuildErrorData(filterContext.Exception),
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };

            filterContext.ExceptionHandled = true;
        }

        private object BuildErrorData(Exception error)
        {
            if(error == null) { return null; }

            var ar = new AjaxResult();

            if (error is ArgumentException)
            {
                ar.Code = AjaxResult.Err_Code_BadRequest;
                ar.Message = error.Message;
            }
            else if (error is System.Runtime.InteropServices.COMException)
            {
                ar.Code = AjaxResult.Err_Code_InternalServer;
                try
                {
                    ar.Message = EmpowerUtils.EmpowerProject.TkErrorDescription(error.HResult);
                }
                catch
                {
                    ar.Message = "Toolkit error";
                }
            }
            else
            {
                ar.Code = AjaxResult.Err_Code_InternalServer;
                ar.Message = error.Message ?? AjaxResult.Err_Msg_InternalServer;
            }

            ar.Data = error.HResult.ToString("X");
            return ar;
        }
    }
}

关于自定义响应结果,需要注意的两点:

  1. 修改HttpContext.Response.StatusCode,asp.net mvc 将根据响应码自动匹配并返回对应的错误信息页面,如下图
    image
    设置ExceptionContext.Result,可返回自定义的ActionResult类型的结果,比如一个Json结构的错误消息,如下图
    image

  2. HttpContext.Response.StatusCodeExceptionContext.Result会冲突,不能同时设置这两个属性,或者说修改了StatusCode后,Result将不再起作用。

注册LogErrorAttribute

注册自定义的处理类,使之生效,替换默认的错误处理,修改APP_Start中的FilterConfig.cs

namespace EmpowerApiService
{
    public class FilterConfig
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            //filters.Add(new HandleErrorAttribute());
            filters.Add(new EmpowerApiService.Filter.LogErrorAttribute());
        }
    }
}

使用[LogError]特性

在需要使用错误处理的ControllerAction上使用特性,就可以捕捉并处理异常

using EmpowerApiService.Filter;

namespace EmpowerApiService.Controllers{

   [LogError]
   public class xxxController : Controller 
   { ... }
}

使用日志组件 NLog

先从Nuget安装NLog,网文说要同时安装NLog.Config,经实测不安装也可以,测试版本是5.2.3
右键点击目标项目,新增项,选择新增配置文件,起名NLog.config
image

编辑文件如下

<?xml version="1.0"?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
	  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	  xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd"
	  autoReload="true"
	  throwException="false"
	  internalLogLevel="Off" internalLogFile="c:\temp\nlog-internal.log">

	<variable name="appName" value="EmpowerApiService" />
	
	<targets>
		<target name="logfile" 
				xsi:type="File"
				fileName="${basedir}/logs/${appName}-${shortdate}.log"
				layout="${longdate}|${uppercase:${level}}|${message}${newline}${callsite}(${callsite-filename:includeSourcePath=False}:${callsite-linenumber})|${exception:format=ToString}"
				maxArchiveFiles="999"
				archiveFileName="${basedir}/logs/${appName}-${shortdate}-${###}.log"
				createDirs="true"
				archiveAboveSize="5242880"
				archiveEvery="Day"
				archiveNumbering="Sequence"
				encoding="UTF-8"
				>
		</target>
	</targets>

	<rules>
		<logger name="*" minlevel="Debug" writeTo="logfile"/>
	</rules>
</nlog>

在需要使用日志的类中实例化日志组件即可使用
image

部署到IIS引发ComException组件异常

IIS 笔记 - Com组件异常

项目引入Com组件,VS调试运行正常,发布并部署到IIS运行报Com组件错误,解决方法:

  1. 打开应用程序池项高级设置中的允许32位应用程序