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

原帖地址:http://www.cnblogs.com/happyframework/archive/2013/06/07/3123162.html

背景


为什么语言引入了异常


一直没有思考过这个问题,但是异常确实让我的编程生活更快乐,今天早上似乎找到了这个问题的答案: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 }


备注


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


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


 

本文链接

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值