Unity、Exception Handling引入MVP

什麼是MVP?在「MVP初探」裏就有講過了,就是一種UI的架構模式。html

簡單的描述一下Unity和Exception Handling Application Block:架構

Unity是一個輕量級的可擴展的依賴注入(DI)容器,支持構造函數,屬性和方法調用注入。構建一個成功應用程序的關鍵是實現很是鬆散的耦合設計。鬆散耦合的應用程序更靈活,更易於維護 。框架

微軟Enterprise Library EHAB(Exception Handling Application Block)提供了一種基於策略(Policy)的異常處理方式,在不一樣的環境中,好比多層架構中不一樣的層次中,咱們能夠定義不一樣的異常處理策略。ide

爲使M/V/P之間更好的解耦,咱們經過引入Enterprise Library的Exception Handling Application Block來實現異常處理,藉助Policy Injection Application Block來實現AOP,即然從2.0開始Unity就有幾個內置的Handler(Authorization/Exception Handling/Logging/Performance Counter/Validation),天然也就引入了Unity。函數

這樣,咱們就能夠作到以AOP的方式處理異常(不單單隻有異常,還能夠是其它的業務無關性處理)。咱們經過Unity的使得P對M的依賴得以解除,同時也大大加強了可擴展性和可配置性。將系統的耦合度也除到最低。工具

實例演練:post

這裏仍是延用《MVP之V和P交互》的例子。ui

首先,咱們來看看Unity如何配置的this

  • 修改配置文件添加配置節
<configSections>   ...   <section name="unity"            type=" Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration, Version=2.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </configSections>
  • 添加Unity節元素
 <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">   </unity>

這個元素節的名稱也就添加配置節時的名稱,二者要相同;spa

  • 添加程序集和命名空間
<assembly name="Handwe.Demo.UnityInMVP" />
    <namespace name="Handwe.Demo.UnityInMVP" />

使得能夠在相應的程序集和命名空間裏查到相對應的類;在這裏也能夠添加別名;

  • 添加容器的擴展節
<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" />
    

用於在Unity容器中擴展攔截;

  • 添加默認(未命名)容器container
<container>

</container>

接着,在這個container裏註冊類型或接口,這裏咱們註冊的是接口,並用於攔載;

  • 註冊接口/類型
<register type="ICalculatorView" mapTo="CalculatorView"/>
      <register type="ICalculate" mapTo="Calculate">
        <interceptor type="TransparentProxyInterceptor"/>
        <interceptionBehavior type="PolicyInjectionBehavior"/>
      </register>

註冊了兩個接口,一個是ICalculatorView並映射到CalculatorView;另一個是ICalculate映射到Calculate;這裏咱們只對ICalculate使用了攔截,有三種攔截器,適用於接口或類型,它是接口類型,因此選擇透明代理攔截器類型TransparentProxyInterceptor,並使用提供的策略攔載行爲PolicyInjectionBehavior.

  • 添加攔截擴展元素
      <extension type="Interception" />
<interception>
        <policy name="policy-exceptionHandler">
          <matchingRule name="auther-rule2" type="MemberNameMatchingRule">
            <constructor>
              <param name="namesToMatch">
                <array type="string[]">
                  <value value="Divide" />
                  <value value="Add" />
                </array>
              </param>
            </constructor>
          </matchingRule>
          <callHandler name="exceptionHandler-handler1" type="Handwe.Demo.UnityInMVP.ExceptionCallHandler, Handwe.Demo.UnityInMVP">
            <constructor>
              <param name="exceptionPolicyName" value="UIExceptionPolicy"/>
              <param name="order" value="1"/>
            </constructor>
          </callHandler>
        </policy>
      </interception>

這裏的攔截策略policy-cexeptionHandler咱們配置爲:使用成員名稱配置規則MemberNameMatchingRule,提供的構造函數接受一個名稱爲nameToMatch,的字符串組string[]的形參,這裏提供了兩個成員,分別是Divide、Add;而處理程序則是咱們經過自定義的,由於咱們要把Unity和EHAB集成;這裏咱們先作下介紹,在ExceptionCallHandler中提供了支持接受兩個形參的構造函數,分別是異常處理策略名稱exceptionPolicyName和處理程序在管道中的執行順序order;那麼這裏的異常處理策略"UIExceptionPolicy"是從哪裏來的呢?其實這個就是咱們在EHAB中配置的異常處理策略的名稱。

有了上面的認識,那麼咱們如今回過頭了看看是若是配置「UIExceptionPloicy」。

 配置EHAB

由於Entlib5不支持使用配置工具來對Unity配置,需要手工配置;EHAB能夠用配置工具來配置;我以藉助配置工具咱們將EHAB的異常處理策略配置爲以下:

  • 添加支持的節
<configSections>
    <section name="exceptionHandling" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=5.0.414.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" requirePermission="true" />
    
  • 具體的配置
  <exceptionHandling>
    <exceptionPolicies>
      <add name="UIExceptionPolicy">
        <exceptionTypes>
          <add name="All Exceptions" type="System.Exception, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
            postHandlingAction="None">
            <exceptionHandlers>
              <add type="Handwe.Demo.UnityInMVP.MessageBoxHandler, Handwe.Demo.UnityInMVP"
                name="Custome Handler" />
            </exceptionHandlers>
          </add>
        </exceptionTypes>
      </add>
    </exceptionPolicies>
  </exceptionHandling>

那麼,如今很清楚的能夠看到咱們經過在Unity中配置的攔截處理經過「UIExceptionPolicy」這個名稱將它們關聯起來。接下來再來看看代碼是如何實現的。具體的能夠看《Exception Handling引入MVP》這裏;

 

代碼的實現

主要的一些代碼在MVP之V和P交互》的例子中已經實現了,在這裏咱們來看看新增的兩個類:分別是MessageBoxHandler、ExceptionCallHandler;

MessageBoxHandler代碼:

  • 引用的程序集

using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling;
using Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration;

 1 namespace Handwe.Demo.UnityInMVP
 2 {
 3     [ConfigurationElementType(typeof(CustomHandlerData))]
 4     public class MessageBoxHandler : IExceptionHandler
 5     {
 6         public MessageBoxHandler(NameValueCollection igonre)
 7         {
 8 
 9         }
10         public Exception HandleException(Exception exception, Guid handlingInstanceId)
11         {
12             MessageBox.Show(exception.Message, "Application Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
13             return exception;
14         }
15     }
1

這個僅僅是在處理異常裏彈出一個消息框;

[ConfigurationElementType(typeof(CustomHandlerData))]

注意這行代碼的使用,它使得能夠在配置文件中配置該處理程序;

public MessageBoxHandler(NameValueCollection igonre)
        {

        }

經過NameValueConllection能夠取得在配置文件的的配置;

 

ExceptionCallHandler的實現代碼:

 1 namespace Handwe.Demo.UnityInMVP
 2 {
 3     public class ExceptionCallHandler : ICallHandler
 4     {
 5         // Fields
 6         private ExceptionPolicyImpl exceptionPolicy;
 7         private int order;
 8 
 9         public ExceptionCallHandler(string exceptionPolicyName, int order)
10         {
11 
12             this.exceptionPolicy = EnterpriseLibraryContainer.Current.GetInstance<ExceptionPolicyImpl>(exceptionPolicyName);
13             this.order = order;
14         }
15 
16         // Methods
17         public ExceptionCallHandler(ExceptionPolicyImpl exceptionPolicy)
18         {
19             this.exceptionPolicy = exceptionPolicy;
20         }
21 
22         public ExceptionCallHandler(ExceptionPolicyImpl exceptionPolicy, int order)
23             : this(exceptionPolicy)
24         {
25             this.order = order;
26         }
27 
28         public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
29         {
30             if (input == null)
31             {
32                 throw new ArgumentNullException("input");
33             }
34             if (getNext == null)
35             {
36                 throw new ArgumentNullException("getNext");
37             }
38             IMethodReturn return2 = getNext()(input, getNext);
39             if (return2.Exception != null)
40             {
41                 try
42                 {
43                     if (!this.exceptionPolicy.HandleException(return2.Exception))
44                     {
45                         return2.ReturnValue = null;
46                         return2.Exception = null;
47                         if (input.MethodBase.MemberType == MemberTypes.Method)
48                         {
49                             MethodInfo methodBase = (MethodInfo)input.MethodBase;
50                             if (methodBase.ReturnType != typeof(void))
51                             {
52                                 return2.Exception = new InvalidOperationException("CantSwallowNonVoidReturnMessage");
53                             }
54                         }
55                     }
56                 }
57                 catch (Exception exception)
58                 {
59                     return2.Exception = exception;
60                 }
61             }
62             return return2;
63         }
64 
65         // Properties
66         public ExceptionPolicyImpl ExceptionPolicy
67         {
68             get
69             {
70                 return this.exceptionPolicy;
71             }
72         }
73 
74         public int Order
75         {
76             get
77             {
78                 return this.order;
79             }
80             set
81             {
82                 this.order = value;
83             }
84         }
85     }
86 
87 }

ExceptionCallHandler須是ICallHandler的實現,下面這個構造函數重載

public ExceptionCallHandler(string exceptionPolicyName, int order)
        {

            this.exceptionPolicy = EnterpriseLibraryContainer.Current.GetInstance<ExceptionPolicyImpl>(exceptionPolicyName);
            this.order = order;
        }

就是使用到的構造函數數,它有兩個形參exceptionPolicyName和order。經過:

this.exceptionPolicy = EnterpriseLibraryContainer.Current.GetInstance<ExceptionPolicyImpl>(exceptionPolicyName);

根據異常處理策略的名稱獲取所相關異常處理配置;

在調用方法或目標方法後肯定是否引起了異常,並經過HandleException檢查是否存在異常對象類型由 System.Exception 參數指定匹配策略項,若是有,則調用與該條目關聯的處理程序。

if (!this.exceptionPolicy.HandleException(return2.Exception))
                    {
                        return2.ReturnValue = null;
                        return2.Exception = null;
                        if (input.MethodBase.MemberType == MemberTypes.Method)
                        {
                            MethodInfo methodBase = (MethodInfo)input.MethodBase;
                            if (methodBase.ReturnType != typeof(void))
                            {
                                return2.Exception = new InvalidOperationException("CantSwallowNonVoidReturnMessage");
                            }
                        }
                    }

這裏是經過被調用的方法是否有無返回值,若是有將方法異常從新引起一個一新的無效操做異常;

小結:

因此經過這樣的設計採用Unity做爲IoC框架,而且經過Unity的Interception Extension實現AOP,不單單是本文提到的Exception Handler。

咱們經過Unity的使得P對M的依賴得以解除,同時也大大加強了可擴展性和可配置性。將系統的耦合度也除到最低。

相關文章
相關標籤/搜索