.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 }

备注

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

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

 

posted on 2013-06-07 08:12  幸福框架  阅读(1996)  评论(6编辑  收藏  举报

导航

我要啦免费统计