[.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 ...
随机推荐
- anatomy app
anatomy app https://appolicious.com/the-best-iphone-apps-for-anatomy-students/ ios anatomy app Compl ...
- css & input type & search icon
css & input type & search icon bug type="search" <input @input="autoSearch ...
- js & while & do while
js & while & do while https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Stat ...
- robots.txt
robots.txt A robots.txt file tells search engine crawlers which pages or files the crawler can or ca ...
- AMP & PWA
AMP & PWA AMP is a web component framework to easily create user-first websites. stories. ads. e ...
- java数据类型(基础篇)
public class note02 { public static void main(String[] args) { //八大基本数据类型 //1.整数 byte num1 = 1; shor ...
- iOS拍照定制之AVCapturePhotoOutput
问题 领导安排任务,写个拍照功能,界面跟系统拍照有点出入 拍完照片,底部显示已拍照片,有个拍照上限[在此不论] 点击已拍照片,可以预览.放大缩小查看 思路 系统拍照肯定不行了,只能定制,没提是否拍照禁 ...
- 解决异常: Execution default-cli of goal org.mybatis.generator:mybatis-generator-maven-plugin:1.3.7:generate failed: Cannot instantiate object of type tk.mybatis.mapper.generator.MapperPlugin -> [Help 1]
mybatis-generator整合通用mapper使用generator插件生成model.mapper时报错: 产生以下错误:↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 解决办法: ...
- 面试必备——Java多线程与并发(一)
1.进程和线程的 (1)由来 1)串行 最初的计算机只能接受一些特定的指令,用户输入一个指令,计算机就做出一个操作.当用户在思考或者输入时,计算机就在等待.显然这样效率低下,在很多时候,计算机都处在等 ...
- POJ-1751(kruskal算法)
Highways POJ-1751 注意这里的样例答案也是对的,只是输出顺序改变,但是这也没关系,因为题目加了特殊判断. #include<iostream> #include<cs ...