zoukankan      html  css  js  c++  java
  • .NET:如何应对边界异常?

    .NET:如何应对边界异常?

    背景

     

    为什么语言引入了异常

     

    一直没有思考过这个问题,但是异常确实让我的编程生活更快乐,今天早上似乎找到了这个问题的答案:exception之于call stack就像break和continue之于while或for、就像return之于method,总结为一句话:异常只是一种返回机制。

     

    为什么异常让程序更简洁

     

    代码里只有正常的处理逻辑。

     

    复制代码
     1         /// <summary>
     2         /// 创建。
     3         /// </summary>
     4         public ActionResult Create(TAggregateRoot item)
     5         {
     6             this.CurrentCommandService.Execute(new TCreateCommand
     7             {
     8                 Aggregate = item
     9             });
    10 
    11             return this.NewtonsoftJson(new
    12             {
    13                 success = true,
    14                 items = this.GetById(item.Id)
    15             });
    16         }
    17 
    18         /// <summary>
    19         /// 修改。
    20         /// </summary>
    21         public ActionResult Update(TAggregateRoot item)
    22         {
    23             this.CurrentCommandService.Execute(new TUpdateCommand
    24             {
    25                 Aggregate = item
    26             });
    27 
    28             return this.NewtonsoftJson(new
    29             {
    30                 success = true,
    31                 items = this.GetById(item.Id)
    32             });
    33         }
    复制代码

     


    我的程序代码基本上也是CQRS的,凡是以写为目的的,都是用void进行声明。

     

     

    异常的处理

     

    异常有五种处理思路,如下图所示:

     

     

    关于这五种处理思路的概要介绍可以参考这篇文章:http://www.cnblogs.com/happyframework/archive/2013/04/09/3010082.html

     

    今天的主要目的是介绍“边界异常处理”。

     

    边界异常处理

     

    当异常到达边界,毫无疑问我们必须进行处理。总体来说,到达边界的异常分为两大类:我们有意抛出的异常和未处理异常,针对这两种异常我们需要不同的处理思路,如:

     

    1. 有意抛出的异常:不希望写入日志,希望显示到UI。
    2. 未处理的异常:希望写入日志,不希望直接显示到UI,希望定制这种异常的显示信息。

     

    一个简单的边界异常处理框架

     

    结构

     

    下图的友好异常就是我们有意抛出的异常或我们能意识到的异常。

     

     

    几个核心类型

     

    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using System.Web.Mvc;
     7 
     8 namespace Happy.Web.Mvc.ExceptionHanding
     9 {
    10     /// <summary>
    11     /// 异常信息提供者接口,如果你希望为异常返回更多的信息,可以实现该接口。
    12     /// </summary>
    13     public interface IExceptionInformationProvider
    14     {
    15         /// <summary>
    16         /// 创建信息。
    17         /// </summary>
    18         object CreateInformation(Exception exception);
    19     }
    20 }
    复制代码

     

    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using System.Web.Mvc;
     7 
     8 using Common.Logging;
     9 using Happy.Web.Mvc.Newtonsoft;
    10 
    11 namespace Happy.Web.Mvc.ExceptionHanding
    12 {
    13     /// <summary>
    14     /// 处理应用程序未捕获的异常。
    15     /// </summary>
    16     [AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
    17     public class WriteExceptionResultAttribute : FilterAttribute, IExceptionFilter
    18     {
    19         /// <inheritdoc />
    20         public void OnException(ExceptionContext filterContext)
    21         {
    22             var exception = filterContext.Exception;
    23 
    24             this.LogException(exception);
    25 
    26             filterContext.Result = ExceptionInformationProviderRegistry.CreateErrorResult(exception);
    27 
    28             filterContext.ExceptionHandled = true;
    29         }
    30 
    31         private void LogException(Exception exception)
    32         {
    33             if (FriendlyExceptionRegistry.Contains(exception.GetType()))
    34             {
    35                 return;
    36             }
    37 
    38             LogManager.GetCurrentClassLogger().Error(exception);
    39         }
    40     }
    41 }
    复制代码

     

    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using System.Web.Mvc;
     7 using System.Data;
     8 
     9 using Happy.ExtensionMethod;
    10 using Happy.DesignByContract;
    11 using Happy.Web.Mvc.Newtonsoft;
    12 
    13 namespace Happy.Web.Mvc.ExceptionHanding
    14 {
    15     /// <summary>
    16     /// 异常信息提供者注册处。
    17     /// </summary>
    18     public static class ExceptionInformationProviderRegistry
    19     {
    20         private static readonly Dictionary<Type, IExceptionInformationProvider> _providers
    21             = new Dictionary<Type, IExceptionInformationProvider>();
    22 
    23         static ExceptionInformationProviderRegistry()
    24         {
    25             Register<OptimisticConcurrencyException>(new Internal.OptimisticConcurrencyExceptionInformationProvider());
    26         }
    27 
    28         /// <summary>
    29         /// 注册提供者。
    30         /// </summary>
    31         public static void Register<TException>(IExceptionInformationProvider provider)
    32             where TException : Exception
    33         {
    34             Register(typeof(TException), provider);
    35         }
    36 
    37         /// <summary>
    38         /// 注册提供者。
    39         /// </summary>
    40         public static void Register(Type exceptionType, IExceptionInformationProvider provider)
    41         {
    42             exceptionType.MustNotNull("exceptionType");
    43             provider.MustNotNull("provider");
    44 
    45             _providers[exceptionType] = provider;
    46         }
    47 
    48         internal static ActionResult CreateErrorResult(Exception exception)
    49         {
    50             exception.MustNotNull("exception");
    51 
    52             var exceptionType = exception.GetType();
    53 
    54             var information = CreateDefaultInformation(exception);
    55             
    56             if (_providers.ContainsKey(exceptionType))
    57             {
    58                 var extInformation = _providers[exceptionType].CreateInformation(exception);
    59 
    60                 foreach (var item in extInformation.ToDictionary())
    61                 {
    62                     information[item.Key] = item.Value;
    63                 }
    64             }
    65 
    66             return new NewtonsoftJsonResult
    67             {
    68                 Data = information
    69             };
    70         }
    71 
    72         private static Dictionary<string, object> CreateDefaultInformation(Exception exception)
    73         {
    74             return new Dictionary<string, object> 
    75             { 
    76                 { "success", false },
    77                 { "exception", exception.GetType().Name },
    78                 { "message",exception.Message }
    79             };
    80         }
    81     }
    82 }
    复制代码

     

    为乐观并发异常自定义返回消息

     

    复制代码
     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 using System.Data;
     7 using System.Web.Mvc;
     8 
     9 using Happy.Web.Mvc.Newtonsoft;
    10 
    11 namespace Happy.Web.Mvc.ExceptionHanding.Internal
    12 {
    13     internal sealed class OptimisticConcurrencyExceptionInformationProvider : ExceptionInformationProvider<OptimisticConcurrencyException>
    14     {
    15         protected override object CreateResult(OptimisticConcurrencyException exception)
    16         {
    17             return new
    18             {
    19                 message = Messages.Error_OptimisticConcurrencyExceptionMessage
    20             };
    21         }
    22     }
    23 }
    复制代码

     

    备注

     

    像微软的异常处理框架都是一个非常好的东西。

     

    合理的利用和使用异常会让程序的结构更加简洁,这些概念只有真正使用了才能深刻的明白。

  • 相关阅读:
    cshtml 中的 AppState = Context.Application 和 控制器中的 Application 也相等
    HangFire快速入门 分布式后端作业调度框架服务
    用RSA加密实现Web登录密码加密传输
    c# MD5及盐值加密
    CentOS目录结构超详细版
    两篇文章带你走入.NET Core 世界:CentOS+Kestrel+Ngnix 虚拟机先走一遍(一)
    利用js实现 禁用浏览器后退
    在.Net Core WebAPI下给Swagger增加导出离线文档功能
    mysql 数据库扫描行数
    EFCore+Mysql仓储层建设(分页、多字段排序、部分字段更新)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3123261.html
Copyright © 2011-2022 走看看