本文链接: https://www.cnblogs.com/hubaijia/p/about-exceptions-3.html

系列文章:

本文目录

Web Api 的错误返回

在使用.net 的 Web Api构建Endpoint对外提供访问时,往往需要统一的错误返回格式。

如果按照前面两篇文章(一)(二)所说,采用带有ErrorCode的异常ErrorCodeException,那么在WebApi中返回错误时,只要返回ErrorCode即可。

代码如下:

  1. [HttpPut]
  2. [Authorize]
  3. public IActionResult Update(UpdatetNickNameRequest request)
  4. {
  5. try
  6. {
  7. long userId = User.GetUserId();
  8. _identityService.SetNickName(userId, request.NickName);
  9. return Ok();
  10. }
  11. catch (IdentityException ex)
  12. {
  13. return new BadRequestObjectResult(ex.ErrorCode);
  14. }
  15. }

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这一关键词:

  1. public int div(int i,int j) throws Exception {...}

throws这一关键词保证了从方法定义上就能知道一个方法抛出什么样的异常,直接借助编译器检查或者IDE的智能提醒,就不会漏掉异常。

而c#中并没有相同的实现,可以见Stackoverflow上的讨论.

那么在 .net 世界中当你调用一个方法时,怎么妥善的知道这个方法抛出什么样的异常呢?知道后我们才能决定是否处理这个异常,还是继续抛出。

目前的答案是:注释!(不要笑,很严肃的解决方案)。

  1. /// <exception cref="IdentityService.IdentityService">这样写Exception注释</exception>
  2. public void SetNickName(long userId, string newNickName)
  3. {
  4. //....
  5. Ensure.NickNameNotExisted(newNickName);
  6. //....
  7. }

当你翻看.net的源码时,会看到所有方法的注释中都良好的列出了有哪些异常。

有几个问题:

  • 我们团队没人写注释,怎么办?
  • 调用方法时,并没有智能提示有哪些异常,所以我们经常忽略
  • 想看异常就得F12看定义,太繁琐。

有很多问题只从技术上没法解决,但我们尽量可以借助一些Review工具来检查团队的代码,提出要求。

此外你会喜欢上 ctrl + k, ctrl+i 这个快捷键的,他能帮助你快速查看注释文档,查看有哪些异常。

visual studio 扩展推荐

在这里,我推荐一个visual studio的扩展,是的,它的名字就叫 Checked Exceptions, 这是我必备的一款扩展。

这款插件会借助注释的形式,协助实现Checked Exception的功能,并且可以快速添加相应注释。

这个有个小提示:如果你从项目伊始采用这款插件,折磨小一点,如果半路使用,那么当作检验团队代码强健性的工具也不错。

此外,这个款扩展可能还有些bug,导致即使注释了Exception还不断提示,所以我平时并不一直启用它,而是在做Code Review时,使用它作为一个检查工具。

这样可以比较好的解决上面提到的Checked Exception的缺点,又利用它的优点。

常见模式

不要重复的抛出

这个只是简单提醒下,见如下代码。

  1. void BadSmellMethod()
  2. {
  3. try
  4. {
  5. .....
  6. }
  7. catch(Exception ex)
  8. {
  9. //.... some thing
  10. // 错误的做法
  11. throw ex;
  12. }
  13. }
  14. void GoodMethod()
  15. {
  16. try
  17. {
  18. .....
  19. }
  20. catch
  21. {
  22. //... some thing
  23. // 错误的做法
  24. throw;
  25. }
  26. }

简单来说就是重复抛出,丢失了引发异常原始方法和当前方法调用之间的StackTrace。

在code analysis中也有相应规则。CA2200.

在asp.net core 中

在捕捉异常时,往往一个异常被一路抛出,或者包装再抛出,直到终点。如果到了终点还没有被捕获,那么就会引发程序中止,这是谁都不想看到的。

在asp.net core中,这个终点就是Controller控制器,所以我们需要在Controller的方法里调用需要的Service,然后兜住所有的可能的异常,这也是可以直接捕获Exception的地方。

代码如下:

  1. [HttpPut]
  2. [Authorize]
  3. public IActionResult Update(UpdatetNickNameRequest request)
  4. {
  5. try
  6. {
  7. long userId = User.GetUserId();
  8. _identityService.SetNickName(userId, request.NickName);
  9. return Ok();
  10. }
  11. catch (IdentityException ex)
  12. {
  13. // 具体异常
  14. //...others
  15. return new BadRequestObjectResult(ex.ErrorCode);
  16. }
  17. catch (OtherException ex)
  18. {
  19. //具体异常
  20. //... others
  21. return new BadRequestObjectResult(ex.ErrorCode);
  22. }
  23. catch(Exception ex)
  24. {
  25. //这里兜住其他未发现的一切异常
  26. //做好日志
  27. //分析后再优化处理
  28. return new BadRequestObjectResult(ErrorCode.Empty);
  29. }
  30. }

在xamarin.forms中

如果你是同道中人,使用xamarin.forms,那么你肯定知道MVVM模式。

异常的终点往往就在MVVM模式中的ViewModel中,比如LoginPageViewModel中,同样ViewModel调用各项Service,你需要在这里兜住所有可能出现的异常。

结语

本文,简要介绍了具体项目中异常的捕捉问题,欢迎大家交流指正。

下篇,我们关注一下 异步编程中的Exception,以及全局错误处理。

谢谢阅读。

[.net] 关于Exception的几点思考和在项目中的使用(三)的更多相关文章

  1. [.net] 关于Exception的几点思考和在项目中的使用(二)

    本文链接: https://www.cnblogs.com/hubaijia/p/about-exceptions-2.html 系列文章: 关于Exception的几点思考和在项目中的使用(一) 关 ...

  2. [.net] 关于Exception的几点思考和在项目中的使用(一)

    本文链接 https://www.cnblogs.com/hubaijia/p/about-exceptions-1.html 关于exception的基本语法和作用,这里不再赘述,下面记录一下我在项 ...

  3. Android -- 思考 -- 为什么要在项目中使用MVP模式

    1,其实有时候一直在找借口不去思考这个问题,总是以赶项目为由,没有很认真的思考这个问题,为什么我们要在项目中使用MVP模式,自己也用MVP也已经做了两个项目,而且在网上也看了不少的文章,但是感觉在高层 ...

  4. 从有约束条件下的凸优化角度思考神经网络训练过程中的L2正则化

    从有约束条件下的凸优化角度思考神经网络训练过程中的L2正则化 神经网络在训练过程中,为应对过拟合问题,可以采用正则化方法(regularization),一种常用的正则化方法是L2正则化. 神经网络中 ...

  5. VS2013中web项目中自动生成的ASP.NET Identity代码思考

    vs2013没有再分webform.mvc.api项目,使用vs2013创建一个web项目模板选MVC,身份验证选个人用户账户.项目会生成ASP.NET Identity的一些代码.这些代码主要在Ac ...

  6. 由项目中一个hash2int函数引发的思考

    hash2int /** * 计算一个字符串的md5折算成int返回 * @param type $str * @return type */ function hash2int($str) { $m ...

  7. 12月中旬项目中出现的几个bug解决方法的思考

    这周做的项目遇到2个费了很多时间才解决的bug,解决之后,发现根本问题并不是什么很难的技术难点,都是因为自己在写代码的过程中,思维不够清晰.还有一个需要再提高的地方就是解决问题的思维,如何快速定位到问 ...

  8. java Exception 出错的栈信息打印到日志中 打印堆栈信息

    我们在开发程序的过程当中,日志是必不可少的工具,这有助于我们分析问题的原因,和出错的详细信息,而java的异常机制又会方便且迅速的帮我们找到出错行的位置. try { .... } catch (Ex ...

  9. 项目中访问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 ...

随机推荐

  1. DeFi 热潮下,NGK将成为下一个财富密码

    区块链正在脱虚向实,处于大规模落地,赋能实体产业的前夜,而在这个关键的关口,一个万亿市场的蓝海正在缓缓生成,成为区块链落地的急先锋,这个先锋便是DeFi. DeFi,即Decentralized Fi ...

  2. [转]自动驾驶平台Apollo 2.5环境搭建

    原文地址:https://blog.csdn.net/jinzhuojun/article/details/80210180,转载主要方便随时查阅,如有版权要求,请及时联系. 我们知道,自动驾驶在学界 ...

  3. 【Python】set 与 list ——如何对列表进行去重?

    在Python中,形如 {1,2,3,4,5} 这样的数据类型叫做"集合",外形酷似列表list [1,2,3,4,5] 但是集合与列表有很多区别,具体表现在以下几方面: List ...

  4. Jupyter Notebook 暗色自定义主题

    这款主题是在jupyter-dark-theme的基础上修改了字体大小和行高,以及显示工具栏.感谢原作者! 安装 下载custom.css文件并移动至~/.jupyter/custom/文件夹下,如果 ...

  5. 物联网网关开发:基于MQTT消息总线的设计过程(上)

    道哥的第 021 篇原创 目录 一.前言 二.网关的作用 2.1 指令转发 2.2 外网通信 2.3 协议转换 2.4 设备管理 2.5 边沿计算(自动化控制) 三.网关内部进程之间的通信 3.1 网 ...

  6. js如何判断一假则假,全真则真

    思路:初始化flag参数为true,一旦有一个为假,则将flag赋值为false,最后返回. 代码如下: checkSupplyWt(list){ var flag = true; list.forE ...

  7. React Context 理解和使用

    写在前面 ​ 鉴于笔者学习此内容章节 React官方文档 时感到阅读理解抽象困难,所以决定根据文档理解写一篇自己对Context的理解,文章附带示例,以为更易于理解学习.更多内容请参考 React官方 ...

  8. go的循环

    目录 go的循环 一.语法 二.语法简写 1.省略第一部分 2.省略第二部分 3.省略第三部分 4.全省略:死循环 5.终极写法,简洁变形 go的循环 Go中只有for循环,没有while循环.因为w ...

  9. 错误信息:...\output\project.axf: error: l6218e: undefined symbol usart1_confing (referred from main.o).

    说明:此文档知识用来记录,顺便给大家作为参考,如有错误的地方请大家多多指正,在下内心定会感激不尽. 前言:关于这个问题,我曾花了一个下午在网上寻找,网上的说法五花八门,我办法试尽,但遍寻无果.由此我认 ...

  10. 七. SpringCloud服务配置

    1. SpringCloud Config概述 1.1 分布式系统面临的配置问题 微服务意味着要将单体应用中的业务拆分成一个一个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务.由于每个服务 ...