<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          dotNET:怎樣處理程序中的異常(實(shí)戰(zhàn)篇)?

          共 6375字,需瀏覽 13分鐘

           ·

          2020-08-05 16:16

          在上篇 《dotNET:怎樣處理程序中的異常(理論篇)》 中講了一些程序中出現(xiàn)異常怎樣處理的理論知識,本文將以代碼的方式來進(jìn)行實(shí)踐。

          環(huán)境

          • dotNET Core:3.1

          • 工具:Rider 2019.3.2

          • 系統(tǒng):macOS 10.15.4

          創(chuàng)建項(xiàng)目

          在 Rider 中創(chuàng)建示例項(xiàng)目 ExceptionDemo ,該項(xiàng)目為 dotNET Core 3.1 的 WebAPI 項(xiàng)目,為了演示方便,不同層級以目錄的方式放在了一個(gè)項(xiàng)目中,創(chuàng)建好的項(xiàng)目目錄結(jié)構(gòu)如下:


          • Controllers

            • UserController:操作用戶的控制器

          • CustomExceptions

            • UserNotFoundException:用戶不存在的自定義異常類

          • Filters

            • CustomerExceptionAttribute:異常結(jié)果處理過濾器

            • ResultFilterAttribute:普通結(jié)果處理過濾器

          • Models

            • CustomExceptionResult:異常返回的處理類

            • CustomExceptionResultModel:異常內(nèi)容的模型類

            • DataResult:普通結(jié)果的返回處理類

            • DataResultModel:普通結(jié)果的內(nèi)容模型類

            • MessageResult:消息結(jié)果的返回處理類

            • MessageResultModel:消息結(jié)果的內(nèi)容模型類

            • ResultModelBase:返回結(jié)果內(nèi)容模型的基類

            • User:示例中用戶的實(shí)體類

          • Repositories

            • IUserRepository:用戶操作數(shù)據(jù)庫的接口

            • UserRepository:用戶操作數(shù)據(jù)庫的實(shí)現(xiàn)類

          • Services

            • IUserService:用戶業(yè)務(wù)層的接口

            • UserService:用戶業(yè)務(wù)層的實(shí)現(xiàn)類

          結(jié)果的返回

          接口的返回可以歸納為三種情況:

          • 正常的請求數(shù)據(jù)的返回

          • 通過判斷需要返回一些消息給前端進(jìn)行提示

          • 異常的返回

          所以上面定義了 DataResult、MessageResult 和 CustomExceptionResult 相關(guān)類來進(jìn)行這三種情況的封裝。

          這三個(gè)類都繼承 ResultModelBase 類,ResultModelBase 類中只定義了 Code

          public?class?ResultModelBase
          {
          ????public?int??Code?{?get;?set;?}
          }

          DataResultModel 類用屬性 Data 來包裝返回結(jié)果

          public?class?DataResultModel:ResultModelBase
          {
          ????public?DataResultModel(object?data,int??code?=?200)
          ????{
          ????????Code?=?code;
          ????????Data?=?data;
          ????}

          ????public?object?Data?{?get;?set;?}
          }

          MessageResultModel 類使用屬性 Message 類返回消息文本

          public?class?MessageResultModel:ResultModelBase
          {
          ????public?MessageResultModel(string?massage,int??code?=?200)
          ????
          {
          ????????Code?=?code;
          ????????Message?=?massage;
          ????}

          ????public?string?Message?{?get;?set;?}
          }

          CustomExceptionResultModel 類中可以傳入 Exception 類型和定義一些其他的相關(guān)屬性

          public?class?CustomExceptionResultModel:ResultModelBase
          {
          ????public?CustomExceptionResultModel(Exception?exception,int??code?=?500)
          ????
          {
          ????????Code?=?code;
          ????????Reason?=?exception.InnerException?!=?null??
          ????????????exception.InnerException.Message?:
          ????????????exception.Message;
          ????}

          ????public?string?Reason?{?get;?set;?}
          }

          DataResult、MessageResult 和 CustomExceptionResult 類都是繼承自O(shè)bjectResult,將相對應(yīng)的 Model 類包裝后通過構(gòu)造函數(shù)賦值給 ObjectResult 的 Value 屬性,用于最后的結(jié)果返回。

          public?class?DataResult:?ObjectResult
          {
          ????public?DataResult(object?data?,?int??code=200?)
          ????????:?base(new?DataResultModel(data,code))
          ????
          {
          ????????StatusCode?=?200;
          ????}
          }
          public?class?MessageResult:ObjectResult
          {
          ????public?MessageResult(string?message,?int??code=200?)
          ????????:?base(new?MessageResultModel(message,code))
          ????
          {
          ????????StatusCode?=?200;
          ????}
          }
          public?class?CustomExceptionResult:ObjectResult
          {
          ????public?CustomExceptionResult(Exception?exception,HttpStatusCode?statusCode,??int??code=500?)
          ????????:?base(new?CustomExceptionResultModel(exception,code))
          ????
          {
          ????????StatusCode?=?(int)statusCode;
          ????}
          }

          使用兩個(gè)過濾器對返回結(jié)果進(jìn)行處理

          public?class?CustomerExceptionAttribute:?IExceptionFilter
          {
          ????public?void?OnException(ExceptionContext?context)
          ????
          {
          ????????HttpStatusCode?status?=?HttpStatusCode.InternalServerError;

          ????????int?code?=?(int)?status;
          ????????//處理各種異常
          ????????if?(context.Exception?is?UserNotFoundException)
          ????????{
          ????????????code?=?500001;
          ????????}
          ????????context.Result?=?new?CustomExceptionResult(context.Exception,status?,code);
          ????????context.ExceptionHandled?=?true;
          ????}
          }

          public?class?ResultFilterAttribute:ActionFilterAttribute
          {
          ????public?override?void?OnResultExecuting(ResultExecutingContext?context)
          ????
          {
          ????????var?objectResult?=?context.Result?as?ObjectResult;
          ????????if?(objectResult?.Value?==?null)
          ????????{
          ????????????context.Result=new?NotFoundObjectResult(new?MessageResult("未找到資源"));
          ????????}

          ????????if?(context.Result?is?MessageResult)
          ????????{
          ????????????context.Result?=?new?MessageResult(objectResult.Value.ToString());
          ????????}
          ????????else?if?(context.Result?is?OkObjectResult?||?context.Result?is?ObjectResult)
          ????????{
          ????????????context.Result?=?new?DataResult(objectResult.Value);
          ????????}
          ????}
          }

          用戶添加接口

          在 UserRepository 中添加 AddUser 方法

          public?User?AddUser(User?user)
          {
          ????int?id=_users.OrderByDescending(x?=>?x.Id).First().Id?+?1;
          ????user.Id?=?id;
          ????_users.Add(user);

          ????return?user;
          }

          示例中沒有實(shí)際操作數(shù)據(jù)庫,_users 是一個(gè) List對象,當(dāng) _users 為 Null 或內(nèi)容為空時(shí),_users.OrderByDescending(x => x.Id).First() 的執(zhí)行就會報(bào)錯(cuò),空對象的問題在實(shí)際程序中無處不在,修改后的代碼如下:

          public?User?AddUser(User?user)
          {
          ????int?id?=?1;
          ????if?(_users.Any())
          ????{
          ????????id=_users.OrderByDescending(x?=>?x.Id).First().Id?+?1;
          ????}
          ????user.Id?=?id;
          ????_users.Add(user);

          ????return?user;
          }

          在 Controller 層的 AddUser 方法也需要對入?yún)?shí)體進(jìn)行檢查

          [HttpPost]
          public?User?AddUser(User?user)
          {
          ????return?_userService.AddUser(user);
          }

          public?class?User
          {
          ????public?int?Id?{?get;?set;?}

          ????[Required(ErrorMessage?=?"用戶名不能為空")]

          ????public?string?Name?{?get;?set;?}
          ????[Required(ErrorMessage?=?"用戶編碼不能為空")]
          ????public?string?Code?{?get;?set;?}
          }

          實(shí)際情況下接口層的入?yún)?shí)體和底層的數(shù)據(jù)實(shí)體需要分開,然后使用 AutoMapper 之類的映射工具進(jìn)行轉(zhuǎn)換,本示例中使用了同一個(gè) User 。

          使用 Postman 進(jìn)行調(diào)用,當(dāng) Name 或 Code 為空時(shí),結(jié)果如下:

          默認(rèn)的返回結(jié)果格式和上面定義的統(tǒng)一的格式有些區(qū)別,大家可以思考下,怎樣使用過濾器的方式將參數(shù)驗(yàn)證的返回信息進(jìn)行統(tǒng)一輸出。

          根據(jù) Id 獲取用戶的名稱

          在 UserRepository 中有根據(jù) Id 獲取 User 對象的方法

          public?User?GetUserById(int?id)
          {
          ????return?_users.Find(x?=>?x.Id?==?id);
          }

          在 UserService 中添加 GetUserName 方法獲取名稱

          public?string?GetUserName(int?id)
          {
          ????User?user=_userRepository.GetUserById(id);
          ????if?(user?==?null)
          ????{
          ????????throw?new?UserNotFoundException($"用戶id:{id}?在數(shù)據(jù)庫不存在"?);
          ????}
          ????return?user.Name;
          }

          當(dāng)通過 id 找不到 User 對象時(shí),可以拋出 UserNotFoundException 異常,如果只是對 user 對象進(jìn)行 Null 判斷然后返回一個(gè)空字符,就弄不清楚是 user 對象不存在還是用戶名為空。

          獲取用戶全名

          下面用一個(gè)獲取用戶全名(包含部門)的業(yè)務(wù)來模擬異常的重新包裝,部門操作的相關(guān)類就不在贅述了,可以在文章最下方的鏈接中查看源碼。

          UserController 中添加了接口方法

          [HttpGet("{id}")]
          public?string?GetFullName(int?id)
          {
          ????return?_userService.GetFullName(id);
          }

          UserService 中添加 GetFullName 方法

          public?string?GetFullName(int?id)
          {
          ????try
          ????{
          ????????User?user?=?GetUserById(id);
          ????????string?deptName?=?_deptService.GetDeptName(user.ParentId);
          ????????//處理其他邏輯
          ????????return?$"{user.Name}[{deptName}]";
          ????}
          ????catch?(Exception?e)
          ????{
          ????????throw?new?UserFullNameGenException($"用戶?Id?為?{id}?的?FullName?生產(chǎn)失敗",e);
          ????}
          }
          • GetUserById 方法和 _deptService.GetDeptName 方法中都可能拋異常,在上次可以捕獲異常然后拋出符合當(dāng)前業(yè)務(wù)的 UserFullNameGenException 異常;

          • 捕獲的異常 e 作為 UserFullNameGenException 異常的 InnerException 傳入,這樣如果層級比較多,通過 InnerException 就可以追溯到最底層的原因。

          當(dāng)輸入?yún)?shù)為用戶不存在的時(shí)候調(diào)用結(jié)果如下:

          當(dāng)輸入?yún)?shù)為用戶的部門不存在時(shí)調(diào)用結(jié)果如下:


          • 通過二次捕獲提示的錯(cuò)誤信息是跟當(dāng)前業(yè)務(wù)有關(guān)的,可以更容易定位問題,更底一層的原因可以在 InnerException 中獲取;

          • 兩次異常是不同原因造成的,但對于這個(gè)業(yè)務(wù)來說就是獲取 FullName 失敗,返回的錯(cuò)誤碼也是一致的 500100 ;

          • 因?yàn)橛辛硕尾东@,異常堆棧信息中只能定位到最上層捕獲異常的地方,如果需要知道更底層的異常堆棧,可以將 InnerException 的堆棧信息進(jìn)行合并。

          最后

          本文以一個(gè)簡單的示例演示了代碼中異常的處理,但重要的不是編碼而是處理問題的思路。具體應(yīng)該怎么做還是需要結(jié)合當(dāng)前的上下文。希望本文對您有所幫助。

          示例源碼:https://github.com/oec2003/DotNetCoreThreeAPIDemo/tree/master/ExceptionDemo

          瀏覽 78
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  成人做爰黄级A片免费看土方 | 黄a在线观看视频 | 2020天天日天天干 | 91性视频 | 色婷婷综合在线网站 |