本文链接: 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的几点思考和在项目中的使用(三)的更多相关文章

  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. Array in Depth

    Array in Depth Array.concat() & Array.push() https://developer.mozilla.org/en-US/docs/Web/JavaSc ...

  2. ts 修改readonly参数

    readonly name = "xxx"; updateValueAndValidity(): void { // this.name = 'a'; (this as { nam ...

  3. DENIEL SOIBIM:真正自律的人都在做这些事情!

    生活节奏的加快,使得很多人无法适从.很多人,浑浑噩噩,庸庸碌碌,觉得一天做了很多事,却总是一事无成.还有些人,觉得得过且过也很好,但是到头来,却让自己陷入慌乱之中.本想要自由自在的生活,但是却往往却被 ...

  4. SPC算力币异军突起,或将跑赢币圈全场

    比特币在出现反弹以后,并没有向上突破,而是回调,目前已经跌破了35000美金.目前,整个市场都在关注着比特币的动向,毕竟,比特币的走势,关注着资本的流向.不过,也有一部分巨鲸们将目光对准了币圈的其它数 ...

  5. 「NGK每日快讯」12.31日NGK第58期官方快讯!

  6. 19_MySQL表的内连接

    本节所涉及的SQL语句: -- 表连接查询 -- 查询每名员工(员工名字,编号)的部门信息(部门编号,部门名称) SELECT e.empno,e.ename,d.dname FROM t_emp e ...

  7. Python算法_爬楼梯(08)

    假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. 示例 1: 输入: 2输出: 2解释: 有两种方 ...

  8. ImportError: No module named _ssl解决方法

    import ssl时出现ImportError: No module named _ssl错误是因为咱安装Python的时候没有把ssl模块编译进去导致的. 解决步骤: 系统没有openssl,手动 ...

  9. 《C++ Primer》笔记 第2章 变量和基本类型

    如果你的数值超过了int表示范围,选用long long 如果你需要使用一个不大的整数,那么明确指定它的类型是signed char或者unsigned char 执行浮点数运算选用double 当一 ...

  10. AJAX 加载效果(遮盖层)

    //创建遮罩层函数体 function createMask(){ var node=document.createElement('div'); node.setAttribute('id','ba ...