[.net] 关于Exception的几点思考和在项目中的使用(三)
本文链接: https://www.cnblogs.com/hubaijia/p/about-exceptions-3.html
系列文章:
本文目录
Web Api 的错误返回
在使用.net 的 Web Api构建Endpoint对外提供访问时,往往需要统一的错误返回格式。
如果按照前面两篇文章(一)、(二)所说,采用带有ErrorCode的异常ErrorCodeException,那么在WebApi中返回错误时,只要返回ErrorCode即可。
代码如下:
[HttpPut]
[Authorize]
public IActionResult Update(UpdatetNickNameRequest request)
{
try
{
long userId = User.GetUserId();
_identityService.SetNickName(userId, request.NickName);
return Ok();
}
catch (IdentityException ex)
{
return new BadRequestObjectResult(ex.ErrorCode);
}
}
ErrorCode类包含了Id, Name, Message属性,方便客户端在收到错误返回后进行处理。
自定义的客户端在接受到Api的返回后,检查HttpStatusCode,如果不成功(不是2xx),那么也直接抛出带有ErrorCode的异常ErrorCodeException即可。
这样,前后端的处理就变得一致和简便。特别是如果你在前端也采用 .net 技术,比如 blazor、xamarin、wpf、winform等等,那前后端可以使用相同的CodeBase。
Exception的捕捉
前面几篇文章,一直在关注Exception的抛出,现在我们来关注一下Exception的捕捉。
那些基础的catch/finally这里就不再赘述,说几个项目中实际出现的现象和问题。
不要吃掉异常
不要吃掉异常有两个层面,一个是直接忽略,比如catch了所有的Exception,并不妥善处理(假处理,就打印一句log,甚至不处理),不过这种失误要不是新手所犯,要不就是编码过程中草草了事的结果。
这里主要注意第二个层面,即catch时不要隐藏异常的类型,即不要catch(Exception ex),这意味着隐藏了异常的类型,吃掉了针对不同的错误采取不同的措施的机会。
微软的code analysis也直接给出了规则 CA1031:不要捕捉一般异常类型.
Checked Exception
CE是确保你所有的异常都得到捕捉,它往往在编译层面提供对Exception的检查,确保你的程序不会因为未处理的异常而终止。
在编写可靠的程序时,程序员需要知道调用的方法抛出什么异常,我是否需要处理,还是包装,还是直接抛出不理,总之我们需要有途径获取这样的信息。
当然,Checked Exception肯定会带来更多的代码量,且在项目初始建立起来,往往需要修改一处,而动整个链条上的代码,一层层的修改。
所以,有些人喜欢CE,认为它带来了规矩,改善了团队代码质量;当然也有些人认为它带来了繁琐。
仁者见仁智者见智,这里不加入这些争辩。争辩1, 争辩2, 争辩3, 争辩4
.net vs java
不得不拿这两门语言进行对比,每个世界都要互相借鉴。
熟悉java语法的同学肯定会知道java方法定义上有throws这一关键词:
public int div(int i,int j) throws Exception {...}
throws这一关键词保证了从方法定义上就能知道一个方法抛出什么样的异常,直接借助编译器检查或者IDE的智能提醒,就不会漏掉异常。
而c#中并没有相同的实现,可以见Stackoverflow上的讨论.
那么在 .net 世界中当你调用一个方法时,怎么妥善的知道这个方法抛出什么样的异常呢?知道后我们才能决定是否处理这个异常,还是继续抛出。
目前的答案是:注释!(不要笑,很严肃的解决方案)。
/// <exception cref="IdentityService.IdentityService">这样写Exception注释</exception>
public void SetNickName(long userId, string newNickName)
{
//....
Ensure.NickNameNotExisted(newNickName);
//....
}
当你翻看.net的源码时,会看到所有方法的注释中都良好的列出了有哪些异常。
有几个问题:
- 我们团队没人写注释,怎么办?
- 调用方法时,并没有智能提示有哪些异常,所以我们经常忽略
- 想看异常就得F12看定义,太繁琐。
有很多问题只从技术上没法解决,但我们尽量可以借助一些Review工具来检查团队的代码,提出要求。
此外你会喜欢上 ctrl + k, ctrl+i
这个快捷键的,他能帮助你快速查看注释文档,查看有哪些异常。
visual studio 扩展推荐
在这里,我推荐一个visual studio的扩展,是的,它的名字就叫 Checked Exceptions, 这是我必备的一款扩展。
这款插件会借助注释的形式,协助实现Checked Exception的功能,并且可以快速添加相应注释。
这个有个小提示:如果你从项目伊始采用这款插件,折磨小一点,如果半路使用,那么当作检验团队代码强健性的工具也不错。
此外,这个款扩展可能还有些bug,导致即使注释了Exception还不断提示,所以我平时并不一直启用它,而是在做Code Review时,使用它作为一个检查工具。
这样可以比较好的解决上面提到的Checked Exception的缺点,又利用它的优点。
常见模式
不要重复的抛出
这个只是简单提醒下,见如下代码。
void BadSmellMethod()
{
try
{
.....
}
catch(Exception ex)
{
//.... some thing
// 错误的做法
throw ex;
}
}
void GoodMethod()
{
try
{
.....
}
catch
{
//... some thing
// 错误的做法
throw;
}
}
简单来说就是重复抛出,丢失了引发异常原始方法和当前方法调用之间的StackTrace。
在code analysis中也有相应规则。CA2200.
在asp.net core 中
在捕捉异常时,往往一个异常被一路抛出,或者包装再抛出,直到终点。如果到了终点还没有被捕获,那么就会引发程序中止,这是谁都不想看到的。
在asp.net core中,这个终点就是Controller控制器,所以我们需要在Controller的方法里调用需要的Service,然后兜住所有的可能的异常,这也是可以直接捕获Exception的地方。
代码如下:
[HttpPut]
[Authorize]
public IActionResult Update(UpdatetNickNameRequest request)
{
try
{
long userId = User.GetUserId();
_identityService.SetNickName(userId, request.NickName);
return Ok();
}
catch (IdentityException ex)
{
// 具体异常
//...others
return new BadRequestObjectResult(ex.ErrorCode);
}
catch (OtherException ex)
{
//具体异常
//... others
return new BadRequestObjectResult(ex.ErrorCode);
}
catch(Exception ex)
{
//这里兜住其他未发现的一切异常
//做好日志
//分析后再优化处理
return new BadRequestObjectResult(ErrorCode.Empty);
}
}
在xamarin.forms中
如果你是同道中人,使用xamarin.forms,那么你肯定知道MVVM模式。
异常的终点往往就在MVVM模式中的ViewModel中,比如LoginPageViewModel中,同样ViewModel调用各项Service,你需要在这里兜住所有可能出现的异常。
结语
本文,简要介绍了具体项目中异常的捕捉问题,欢迎大家交流指正。
下篇,我们关注一下 异步编程中的Exception,以及全局错误处理。
谢谢阅读。
[.net] 关于Exception的几点思考和在项目中的使用(三)的更多相关文章
- [.net] 关于Exception的几点思考和在项目中的使用(二)
本文链接: https://www.cnblogs.com/hubaijia/p/about-exceptions-2.html 系列文章: 关于Exception的几点思考和在项目中的使用(一) 关 ...
- [.net] 关于Exception的几点思考和在项目中的使用(一)
本文链接 https://www.cnblogs.com/hubaijia/p/about-exceptions-1.html 关于exception的基本语法和作用,这里不再赘述,下面记录一下我在项 ...
- Android -- 思考 -- 为什么要在项目中使用MVP模式
1,其实有时候一直在找借口不去思考这个问题,总是以赶项目为由,没有很认真的思考这个问题,为什么我们要在项目中使用MVP模式,自己也用MVP也已经做了两个项目,而且在网上也看了不少的文章,但是感觉在高层 ...
- 从有约束条件下的凸优化角度思考神经网络训练过程中的L2正则化
从有约束条件下的凸优化角度思考神经网络训练过程中的L2正则化 神经网络在训练过程中,为应对过拟合问题,可以采用正则化方法(regularization),一种常用的正则化方法是L2正则化. 神经网络中 ...
- VS2013中web项目中自动生成的ASP.NET Identity代码思考
vs2013没有再分webform.mvc.api项目,使用vs2013创建一个web项目模板选MVC,身份验证选个人用户账户.项目会生成ASP.NET Identity的一些代码.这些代码主要在Ac ...
- 由项目中一个hash2int函数引发的思考
hash2int /** * 计算一个字符串的md5折算成int返回 * @param type $str * @return type */ function hash2int($str) { $m ...
- 12月中旬项目中出现的几个bug解决方法的思考
这周做的项目遇到2个费了很多时间才解决的bug,解决之后,发现根本问题并不是什么很难的技术难点,都是因为自己在写代码的过程中,思维不够清晰.还有一个需要再提高的地方就是解决问题的思维,如何快速定位到问 ...
- java Exception 出错的栈信息打印到日志中 打印堆栈信息
我们在开发程序的过程当中,日志是必不可少的工具,这有助于我们分析问题的原因,和出错的详细信息,而java的异常机制又会方便且迅速的帮我们找到出错行的位置. try { .... } catch (Ex ...
- 项目中访问controller报错:HTTP Status 500 - Servlet.init() for servlet spring threw exception
直接访问controller路径http://localhost:8080/index报错: HTTP Status 500 - Servlet.init() for servlet spring t ...
随机推荐
- js 反应&行动
反应 class Reaction { _page = 1; get page() { return this._page; } set page(newValue) { this._page = n ...
- python进阶(1)Lambda表达式
Lambda表达式 lambda表示的是匿名函数,不需要用def来声明,一句话就可以声明出一个函数 语法 函数名 = lambda 参数:返回值 注意点 1.函数的参数可以有多个,多个参数之间用逗号隔 ...
- 死磕以太坊源码分析之EVM如何调用ABI编码的外部方法
死磕以太坊源码分析之EVM如何调用ABI编码的外部方法 配合以下代码进行阅读:https://github.com/blockchainGuide/ 写文不易,给个小关注,有什么问题可以指出,便于大家 ...
- 微信小程序:页面全局参数(注意不是小程序的全局变量globalData)
为什么要使用页面全局参数:方便使用数据. 由于总页数需要再另外的一个方法中使用,所以要把总页数变成一个页面全局参数.因为取数据使用this.xxx即可,中间不用加data,给页面全局参数赋值页方便,直 ...
- JAVA基础(零)—— 踩坑与错误(常更)
JAVA基础(零)-- 踩坑与错误(常更) 1 坑 考虑输入为null的情况 自动转换 x/Math.pow(10,i)*Math.pow(10,i) //由于math.pow()返回double类型 ...
- nacos服务注册之服务器端Raft
Raft是持久化,数据存储在\nacos\data\naming\data目录 nacos启动后首先从数据存储目录加载数据 Raft协议中节点只有一个LEADER,只有LEADER节点负责数据写入,F ...
- Gitlab与Sonarqube整合-代码提交自动检测
目录 概述 准备工作 postgres sonarqube gitlab gitlab-runner Gitlab-runner容器 注册Gitlab-runner Sonarqube gitlab ...
- Hi3559AV100板载开发系列-pthread_create()下V4L2接口MJPEG像素格式的VIDIOC_DQBUF error问题解决-采用阻塞方式下select监听
最近一直加班加点进行基于Hi3559AV100平台的BOXER-8410AI板载开发,在开发的过程中,遇到了相当多的问题,其一是板载的开发资料没有且功能不完整,厂家不提供太多售后技术支持,厂家对部分 ...
- SpringMVC-05 Json交互处理
SpringMVC-05 Json交互处理 Json 1.什么是JSON? JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别 ...
- WPF 基础 - 点击事件的执行顺序及 Button 点击事件的特殊性
1. 点击事件的执行顺序 PreviewMouseLeftButtonDown PreviewMouseDown MouseLeftButtonDown MouseDown PreviewMouseL ...