.NETCore WebApi中实现异常拦截器(AOP)

一、异常拦截思路

.NET Core WebApi基础入门项目源码下载

  新建ExceptionFilter这个异常的拦截器,用于记录工程抛异常并做对应回调处理。

二、实现核心

2.1、异常拦截类

/***
*	Title:".NET Core WebApi" 项目
*		主题:异常拦截
*	Description:
*		功能:实现拦截异常内容记录到日志
*	Date:2021
*	Version:0.1版本
*	Author:Coffee
*	Modify Recoder:
*/

using log4net;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Utils;

namespace Filters
{
    public class ExceptionFilter
    {
        private readonly RequestDelegate _requestDelegate;

        private readonly ILog _log = LogManager.GetLogger(WebApi_Learn.Startup.repository.Name, typeof(ExceptionFilter));

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="requestDelegate">请求委托</param>
        public ExceptionFilter(RequestDelegate requestDelegate)
        {
            _requestDelegate = requestDelegate;

        }

        /// <summary>
        /// 回调
        /// </summary>
        /// <param name="context">Http内容</param>
        /// <returns></returns>
        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _requestDelegate(context);
            }
            catch (Exception ex) 
            {
                context.Response.StatusCode = 500;

                _log.Error("服务器错误:" + ex.Message);
                await ResponseHelper.HandleExceptionAsync(500, "服务器错误:"+ ex.Message);
            }
        }

    }//Class_end
}

2.2、Http响应帮助类

/***
*	Title:".NET Core WebApi" 项目
*		主题:响应帮助类
*	Description:
*		功能:
*		    1、异常处理回调
*		    2、统一请求页面实体
*	Date:2021
*	Version:0.1版本
*	Author:Coffee
*	Modify Recoder:
*/

using log4net;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Utils
{
    public class ResponseHelper
    {
        #region   基础参数
        //服务接口
        public static IServiceProvider serviceProvider;

        #endregion 

        /// <summary>
        /// 异常处理回调
        /// </summary>
        /// <param name="statusCode">html状态码</param>
        /// <param name="msg">消息</param>
        /// <returns></returns>
        public static Task HandleExceptionAsync(int statusCode, string msg)
        {
            var data = new { code = statusCode, msg = msg };
            string text = JsonConvert.SerializeObject(data);

            var response = HttpCurrent.Response;
            if (string.IsNullOrEmpty(response.ContentType))
            {
                //跨域的时候注意,不带header没法接收回调
                response.Headers.Add("Access-Control-Allow-Origin", "*");
                response.Headers.Add("Access-Control-Allow-Credentials", "true");
                //因为这个是json
                response.ContentType = "application/json;charset=utf-8";
                response.StatusCode = 200;
                response.ContentLength = text.Length;
                return response.WriteAsync(text);
            }
            else
            {
                return response.WriteAsync(text);
            }
        }


        /// <summary>
        /// 统一请求页面实体
        /// </summary>
        public static HttpContext HttpCurrent
        {
            get
            {
                object factory = serviceProvider.GetService(typeof(IHttpContextAccessor));
                HttpContext context = ((IHttpContextAccessor)factory).HttpContext;
                return context;
            }
        }

    }//Class_end
}

三、在中间件中调用

3.1、在Startup类中的Configure方法中调用异常过滤

 //使用我们的异常拦截中间件
 Utils.ResponseHelper.serviceProvider = app.ApplicationServices;
 app.UseMiddleware<Filters.ExceptionFilter>();

 3.2、调用的接口

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace WebApi_Learn.Controllers
{

    [ApiController]
    [Route("api/[controller]/[action]")]
    public class WeatherForecastController : ControllerBase
    {
        private static readonly string[] Summaries = new[]
        {
            "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
        };

        private readonly ILogger<WeatherForecastController> _logger;

        public WeatherForecastController(ILogger<WeatherForecastController> logger)
        {
            _logger = logger;
        }


        /// <summary>
        /// 获取到当前的天气信息
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public IEnumerable<WeatherForecast> Get()
        {
            var rng = new Random();
            return Enumerable.Range(1, 5).Select(index => new WeatherForecast
            {
                Date = DateTime.Now.AddDays(index),
                TemperatureC = rng.Next(-20, 55),
                Summary = Summaries[rng.Next(Summaries.Length)]
            })
            .ToArray();
        }


        /// <summary>
        /// 获取本地文件
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public Task<IActionResult> GetPath()
        {
            string filePathAndName = @"C:/test.txt";
            if (System.IO.File.Exists(filePathAndName))
            {
                FileInfo file = new FileInfo(filePathAndName);
                return GetFileStreamResult(file);
            }
            else
            {
                throw new Exception();
            }


        }

        /// <summary>
        /// 获取到文件流结果
        /// </summary>
        /// <param name="fileInfo">FileInfo文件</param>
        /// <returns>返回FileStreamResult</returns>
        private async Task<IActionResult> GetFileStreamResult(FileInfo fileInfo)
        {
            if (fileInfo == null) return NotFound();


            var memoryStream = new MemoryStream();
            using (var stream = new FileStream(fileInfo.FullName, FileMode.Open))
            {
                await stream.CopyToAsync(memoryStream);
            }
            memoryStream.Seek(0, SeekOrigin.Begin);

            //文件名必须编码,否则会有特殊字符(如中文)无法在此下载。
            string encodeFilename = System.Net.WebUtility.UrlEncode(fileInfo.Name);
            Response.Headers.Add("Content-Disposition", "attachment; filename=" + encodeFilename);
            return new FileStreamResult(memoryStream, "application/octet-stream");//文件流方式,指定文件流对应的ContenType。
        }



    }
}

3.3、运行结果和日志

四、AOP介绍

AOP内容来自:AOP 的详细说明以及基本的使用

4.1、AOP简介

  AOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。

​   OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的复用。

而AOP技术则恰恰相反,它利用一种称为“横切”的技术。

​   剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。AOP代表的是一个横向的关系,如果说“对象”是一个空心的圆柱体,其中封装的是对象的属性和行为;那么面向方面编程的方法,就仿佛一把利刃,将这些空心圆柱体剖开,以获得其内部的消息。而剖开的切面,也就是所谓的“方面”了。然后它又以巧夺天功的妙手将这些剖开的切面复原,不留痕迹。

在这里插入图片描述

4.2、AOP作用

  想象下面的场景,开发中在多个模块间有某段重复的代码,我们通常是怎么处理的?显然,没有人会靠“复制粘贴”吧。在传统的面向过程编程中,我们也会将这段代码,抽象成一个方法,然后在需要的地方分别调用这个方法,这样当这段代码需要修改时,我们只需要改变这个方法就可以了。然而需求总是变化的,有一天,新增了一个需求,需要再多出做修改,我们需要再抽象出一个方法,然后再在需要的地方分别调用这个方法,又或者我们不需要这个方法了,我们还是得删除掉每一处调用该方法的地方。实际上涉及到多个地方具有相同的修改的问题我们都可以通过 AOP 来解决。


五、其他AOP资料

spring aop 及实现方式

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛奶咖啡13

我们一起来让这个世界有趣一点…

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值