《Asp.Net Core3 + Vue3入坑教程》 - 6.异常处理与UserFriendlyException
简介
《Asp.Net Core3 + Vue3入坑教程》 此教程适合新手入门或者前后端分离尝试者。可以根据图文一步一步进操作编码也可以选择直接查看源码。每一篇文章都有对应的源码
目录
《Asp.Net Core3 + Vue3入坑教程》系列教程目录
Asp.Net Core后端项目
- 后端项目搭建与Swagger配置步骤
- 配置CROS策略解决跨域问题
- AutoMapper & Restful API & DI
- EF Core & Postgresql
- .Net Core 3升级成 .Net 5 & JWT
- (本文)异常处理与UserFriendlyException
Vue3 前端项目
- 使用vue-cli创建vue项目
- (暂未发表敬请期待...)使用Ant Design of Vue编写页面 & vue-router 初试
- (暂未发表敬请期待...)将Antd导航菜单与vue-router绑定
- (暂未发表敬请期待...) 保存用户登入状态vuex初试
本文简介
本文为《Asp.Net Core3 + Vue3入坑教程》系列教程的后端第六篇 - 异常处理与UserFriendlyException上文已经为Simple项目升级了SDK并且应用了JWT,本文继续为Simple项目增加异常处理与使用友好异常(UserFriendlyException)。
为什么需要使用友好异常的方式进行开发呢?
在很多情况下,我们在一个方法中往往包含着校验参数与返回结果两个动作,这时候我们的返回结果就需要考虑用对象来包裹校验结果与返回结果。 如果我们使用友好异常,默认方法能顺利通过校验并返回正确的结果,如果校验出现失败的情况则将失败原因通过友好异常的方式返回给调用者,可以让方法的返回内容不需要考虑校验的结果,代码更简洁明了!
用户友好参照了开源项目ABP项目 https://docs.abp.io/zh-Hans/abp/latest/Exception-Handling
异常处理与UserFriendlyException
第一步先增加测试代码,修改SqlCommanderRepo.cs
代码调整如下:
using Simple_Asp.Net_Core.Models;
using Simple_Asp.Net_Core.ServiceProvider;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Simple_Asp.Net_Core.Data
{
public class SqlCommanderRepo : ICommanderRepo
{
private readonly CommanderContext _context;
public SqlCommanderRepo(CommanderContext context)
{
_context = context;
}
public void CreateCommand(Command cmd)
{
if (cmd == null)
{
throw new ArgumentNullException(nameof(cmd));
}
_context.Commands.Add(cmd);
}
public void DeleteCommand(Command cmd)
{
if (cmd == null)
{
throw new ArgumentNullException(nameof(cmd));
}
_context.Commands.Remove(cmd);
}
public IEnumerable<Command> GetAllCommands()
{
return _context.Commands.ToList();
}
public Command GetCommandById(int id)
{
if (id == 0)
throw new Exception("id不能为0!");
return _context.Commands.First(p => p.Id == id);
}
public bool SaveChanges()
{
return (_context.SaveChanges() >= 0);
}
public void UpdateCommand(Command cmd)
{
//Nothing
}
}
}
运行项目,调用接口api/commands/{id}接口,当请求参数id设置为0时,后端会抛出异常信息。
当前的异常信息将程序内部内容都暴露出来,并且返回信息也不清晰,调用者难以处理。

接着在ServiceProvider文件夹下增加自定义异常类UserFriendlyException.cs
代码如下:
using System;
namespace Simple_Asp.Net_Core.ServiceProvider
{
public class UserFriendlyException : Exception
{
public UserFriendlyException(string message) : base(message)
{
}
public UserFriendlyException(string message, Exception inner) : base(message, inner)
{
}
}
}
在ServiceProvider文件夹下增加类ExceptionHandler.cs,用来处理异常
在捕捉到程序异常的时候需要写入日志方便问题追踪
代码如下:
using Microsoft.AspNetCore.Diagnostics;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using System.Text;
using System.Threading.Tasks;
namespace Simple_Asp.Net_Core.ServiceProvider
{
public class ExceptionHandler
{
public static Task ErrorEvent(HttpContext context)
{
var feature = context.Features.Get<IExceptionHandlerFeature>();
var error = feature?.Error;
if (error.GetType() == typeof(UserFriendlyException))
{
SetResponse(context);
var content = GetApiResponse(error.Message);
return context.Response.WriteAsync(JsonConvert.SerializeObject(content), Encoding.UTF8);
}
else
{
// 写入日志
// error.Message
// error.StackTrace
SetResponse(context);
var content = GetApiResponse("程序发生错误,请联系客服!");
return context.Response.WriteAsync(JsonConvert.SerializeObject(content), Encoding.UTF8);
}
}
/// <summary>
/// 解决异常消息返回跨域问题
/// </summary>
private static void SetResponse(HttpContext context)
{
context.Response.Clear();
context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
context.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET");
context.Response.ContentType = "application/json";
}
/// <summary>
/// 响应Response
/// </summary>
private static ErrorResponse GetApiResponse(string message)
{
return new ErrorResponse() { success = false, message = message };
}
private class ErrorResponse
{
public bool success { get; set; }
public bool Success { get { return success; } }
public string message { get; set; }
public string Message { get { return message; } }
}
}
}
调整Startup.cs,增加异常捕捉
代码如下:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json.Serialization;
using Simple_Asp.Net_Core.Data;
using Simple_Asp.Net_Core.ServiceProvider;
using System;
namespace Simple_Asp.Net_Core
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddJWT();
services.AddDbContext<CommanderContext>(options =>
options.UseNpgsql("Host=localhost;Database=postgres;Username=postgres;Password=123456"));
services.AddCORS();
services.AddMvc();
services.AddSwagger();
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
services.AddScoped<ICommanderRepo, SqlCommanderRepo>();
services.AddControllers().AddNewtonsoftJson(s =>
{
s.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "ApiHelp V1");
});
}
app.UseExceptionHandler(builder => builder.Run(async context => await ExceptionHandler.ErrorEvent(context)));
app.UseCors("CorsTest");
app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
}
}
}
启动项目,调用api/commands/{id}接口,可以看出后端的接口发生了异常,此时的异常比较清晰。

最后我们将SqlCommanderRepo.cs里的异常改为友好异常
再次修改SqlCommanderRepo.cs
代码调整如下:
using Simple_Asp.Net_Core.Models;
using Simple_Asp.Net_Core.ServiceProvider;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Simple_Asp.Net_Core.Data
{
public class SqlCommanderRepo : ICommanderRepo
{
private readonly CommanderContext _context;
public SqlCommanderRepo(CommanderContext context)
{
_context = context;
}
public void CreateCommand(Command cmd)
{
if (cmd == null)
{
throw new ArgumentNullException(nameof(cmd));
}
_context.Commands.Add(cmd);
}
public void DeleteCommand(Command cmd)
{
if (cmd == null)
{
throw new ArgumentNullException(nameof(cmd));
}
_context.Commands.Remove(cmd);
}
public IEnumerable<Command> GetAllCommands()
{
return _context.Commands.ToList();
}
public Command GetCommandById(int id)
{
if (id == 0)
throw new Exception("id不能为0!");
return _context.Commands.First(p => p.Id == id);
}
public bool SaveChanges()
{
return (_context.SaveChanges() >= 0);
}
public void UpdateCommand(Command cmd)
{
//Nothing
}
}
}
最后启动项目,调用api/commands/{id}接口,这时候我们可以得到友好的提示!

总结
本文为Simple项目增加异常处理与使用友好异常(UserFriendlyException),在捕捉到程序异常的时候需要写入日志方便问题追踪!
目前Simple项目还未使用日志组件,后续会补上
异常捕捉为了能够将异常内容进行收集,并且能以统一的方式返回给客户端,保证服务器的安全、帮助我们追踪问题并且客户端的体验也能有所保证。
异常捕捉结合友好异常的方式能够为我们减少代码量,并且让代码更直观明了,推荐大家一试!
GitHub源码
注意:源码调试过程中如果出现xml文件路径错误,需要参照第一章(后端项目搭建与Swagger配置步骤)Swagger配置“配置XML 文档文件”步骤,取消勾选然后再选中 ,将XML路径设置成与你的电脑路径匹配!
参考资料
ABP开源项目异常处理 https://docs.abp.io/zh-Hans/abp/latest/Exception-Handling
《Asp.Net Core3 + Vue3入坑教程》 - 6.异常处理与UserFriendlyException的更多相关文章
- 《Asp.Net Core3 + Vue3入坑教程》-Net Core项目搭建与Swagger配置步骤
简介 <Asp.Net Core3 + Vue3入坑教程> 此教程仅适合新手入门或者前后端分离尝试者.可以根据图文一步一步进操作编码也可以选择直接查看源码.每一篇文章都有对应的源码 教程后 ...
- 《Asp.Net Core3 + Vue3入坑教程》 - Vue 1.使用vue-cli创建vue项目
简介 <Asp.Net Core3 + Vue3入坑教程> 此教程适合新手入门或者前后端分离尝试者.可以根据图文一步一步进操作编码也可以选择直接查看源码.每一篇文章都有对应的源码 目录 & ...
- Vue入坑教程(二)——项目结构详情介绍
之前已经介绍了关于Vue的脚手架vue-cli的安装,以及一些文件目录介绍.具体可以查看<vue 入坑教程(一)--搭建vue-cli脚手架> 下面简单说一下具体的文件介绍 (一) pac ...
- Docker 入坑教程笔记
Docker 入坑教程笔记 视频网址B站:点这里 查询命令 man docker 简单启动和退出 docker run --name [容器名] -i -t ubuntu /bin/bash 交互启动 ...
- Vue2.0史上最全入坑教程(下)—— 实战案例
书接上文 前言:经过前两节的学习,我们已经可以创建一个vue工程了.下面我们将一起来学习制作一个简单的实战案例. 说明:默认我们已经用vue-cli(vue脚手架或称前端自动化构建工具)创建好项目了 ...
- Vue入坑教程(一)——搭建vue-cli脚手架
1. Vue简介 详细内容可以参考官网Vue.js 1)兼容性 Vue 不支持 IE8 及以下版本,因为 Vue 使用了 IE8 无法模拟的 ECMAScript 5 特性.但它支持所有兼容 ECMA ...
- Vue2.0史上最全入坑教程(上)—— 搭建Vue脚手架(vue-cli)
ps: 想了解更多vue相关知识请点击VUE学习目录汇总 Vue作为前端三大框架之一截至到目前在github上以收获44,873颗星,足以说明其以悄然成为主流.16年10月Vue发布了2.x版本,经过 ...
- vue入坑教程(一)
1.脚手架搭配webpack的安装 (1)需要检查自己的电脑有没有安装node和npm 如果没有安装可以参考官网,以及安装的步骤 官方中文网地址:http://nodejs.cn/ (2)下载webp ...
- vue入坑教程(三)vue父子组件之间互相调用方法以及互相传递数据
1.父组件调用子组件的方法 父组件: <template> <div> <button v-on:click="clickParent">点击& ...
随机推荐
- Chapter Zero 0.2.3 显示适配器
显示适配器(Video Graphics Array,VGA) 不看后悔!!深入了解显卡!!!走你! 我们常常会调试显示器的分辨率,一般对于图像的显示重点在于分辨率与颜色深度, 每个图像显示的颜色会占 ...
- 电影推荐系统---协同过滤算法(SVD,NMF)
SVD 参考 https://www.zybuluo.com/rianusr/note/1195225 1 推荐系统概述 1.1 项目安排 1.2 三大协同过滤 1.3 项目开发工具 ...
- Mybatis基础:Mybatis映射配置文件,Mybatis核心配置文件,Mybatis传统方式开发
一.Mybatis快速入门 1.1 框架介绍 框架是一款半成品软件,我们可以基于这个半成品软件继续开发,来完成我们个性化的需求! 框架:大工具,我们利用工具,可以快速开发项目 (mybatis也是一个 ...
- 如何实现一个简易版的 Spring - 如何实现 @Component 注解
前言 前面两篇文章(如何实现一个简易版的 Spring - 如何实现 Setter 注入.如何实现一个简易版的 Spring - 如何实现 Constructor 注入)介绍的都是基于 XML 配置文 ...
- asp.net 从Excel表导入数据到数据库中
http://www.cnblogs.com/hfzsjz/archive/2010/12/31/1922901.html http://hi.baidu.com/ctguyg/item/ebc857 ...
- value-key
value-key object 如果 Select 的绑定值为对象类型,请务必指定 value-key 作为它的唯一性标识. value-key 作为 value 唯一标识的键名,绑定值为对象类型时 ...
- 前端安全 All In One
前端安全 All In One refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只允许注册用户才可以访问!
- Python Quiz & Python Exercise
Python Quiz & Python Exercise https://www.w3schools.com/quiztest/quiztest.asp?qtest=PYTHON https ...
- SPC空投搅动市场,NGK算力持有者或成大赢家!
要说公链3.0的顶级代表是谁,恐怕非NGK公链莫属.NGK公链自诞生以来,便在区块链市场掀起了一波又一波热潮,并不断地打造着属于自己独有的生态体系.从NGK公链到Baccarat,再到呼叫河马,几乎每 ...
- 【转】ROS之topic和service通信比较
实验速度 1. via topic 上图是以前ROS课上做的一个实验,内容是测试一个publisher和一个subscriber之间通讯所用的时间.两个node都很简单,publisher发送一个字符 ...