運用Unity實現AOP攔截器[結合異常記錄實例]

 

 

本篇文章將經過Unity實現Aop異常記錄功能;有關Unity依賴注入能夠看前兩篇文章:html

1:運用Unity實現依賴注入[結合簡單三層實例] spring

2:運用Unity實現依賴注入[有參構造注入]  編程

另早期寫過一個利用Spring.net實現相同的功能:spring.net結合普通三層(實現IOC 及AOP中的異常記錄功能)app

 

一:理論知識ide

AOP(Aspect-Oriented Programming,面向切面的編程),它是能夠經過預編譯方式和運行期動態代理實如今不修改源代碼的狀況下給程序動態統一添加功能的一種技術。它是一種新的方法論,它是對傳統OOP編程的一種補充。   OOP是關注將需求功能劃分爲不一樣的而且相對獨立,封裝良好的類,並讓它們有着屬於本身的行爲,依靠繼承和多態等來定義彼此的關係;AOP是但願可以將通用需求功能從不相關的類當中分離出來,可以使得不少類共享一個行爲,一旦發生變化,沒必要修改不少類,而只須要修改這個行爲便可。   AOP是使用切面(aspect)將橫切關注點模塊化,OOP是使用類將狀態和行爲模塊化。在OOP的世界中,程序都是經過類和接口組織的,使用它們實現程序的核心業務邏輯是十分合適。可是對於實現橫切關注點(跨越應用程序多個模塊的功能需求)則十分吃力,好比日誌記錄,驗證等模塊化

Unity默認提供了三種攔截器:TransparentProxyInterceptor、InterfaceInterceptor、VirtualMethodInterceptor。函數

TransparentProxyInterceptor:代理實現基於.NET Remoting技術,它可攔截對象的全部函數。缺點是被攔截類型必須派生於MarshalByRefObject。ui

InterfaceInterceptor:只能對一個接口作攔截,好處時只要目標類型實現了指定接口就能夠攔截。編碼

VirtualMethodInterceptor:對virtual函數進行攔截。缺點是若是被攔截類型沒有virtual函數則沒法攔截,這個時候若是類型實現了某個特定接口能夠改用spa

InterfaceInterceptor。

 

二:實例介紹

本實例是經過Unity實現異常的統一記錄,解決之前在解決方法不一樣地方出現重複異常記錄狀況;

圖中一樣是基於咱們前兩篇文章講解依賴注入時的分層結構;增長對log4net.dll引用來記錄異常的內容;

若要了解分層狀況看前一篇運用Unity實現依賴注入[結合簡單三層實例],本文側重講解AOP的實現;

 

三:實例編碼

1:首先了解公共助手層Command;其中Log4netFile加載log4net配置信息,特別要注意assembly

using log4net;
using log4net.Core;
using System.Reflection;

[assembly: log4net.Config.XmlConfigurator(Watch = true)]
namespace Command
{
    public  class Log4NetFile
    {
        private ILog logger;
        public Log4NetFile()
        {
            logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
            log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo("Log4Net.config"));
        }

        public void Log(string message)
        {
            logger.Warn(message);
        }
       
        public void Log(Exception ex)
        {
            logger.Warn("異常的內容:", ex);
        }
    }
}

而ExceptionLogBehavior類是咱們異常攔截器,也是本篇的重點,其中咱們繼承IInterceptionBehavior接口,不只能夠查看傳入的參數,還能夠對它進行統一的異常處理;getNext()(input, getNext)就是重調運行;

using Microsoft.Practices.Unity.InterceptionExtension;
namespace Command
{
    public class ExceptionLogBehavior:IInterceptionBehavior
    {
        /// <summary>
        /// 獲取當前行爲須要攔截的對象類型接口。
        /// </summary>
        /// <returns>全部須要攔截的對象類型接口。</returns>
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }
        /// <summary>
        /// 經過實現此方法來攔截調用並執行所需的攔截行爲。
        /// </summary>
        /// <param name="input">調用攔截目標時的輸入信息。</param>
        /// <param name="getNext">經過行爲鏈來獲取下一個攔截行爲的委託。</param>
        /// <returns>從攔截目標得到的返回信息。</returns>
        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine("執行前");
            IMethodReturn retvalue = getNext()(input, getNext);
           
            #region 參數部分
            Console.WriteLine("-------------參數內容---------------");
            for (int i = 0; i < input.Arguments.Count; i++)
            {
                var parameter = input.Arguments[i];
                Console.WriteLine(string.Format("第{0}個參數值爲:{1}", i+1, parameter.ToString()));
            }
            Console.WriteLine("------------------------------------");
            #endregion

            #region 異常處理部分
            if (retvalue.Exception == null)
            {
                Console.WriteLine("執行成功,無異常");
            }
            else
            {
                //記錄異常的內容 好比Log4Net等
                new Log4NetFile().Log("異常的內容爲:" + retvalue.Exception.Message);
                //retvalue.Exception設爲null表示異常已經被處理過了
                retvalue.Exception = null;
            }
            #endregion
            Console.WriteLine("完成");
            return retvalue; 
        }

        /// <summary>
        /// 獲取一個<see cref="Boolean"/>值,該值表示當前攔截行爲被調用時,是否真的須要執行
        /// 某些操做。
        /// </summary>
        public bool WillExecute
        {
            get { return true; }
        }
    }

2:邏輯層咱們故意讓它拋出異常內容

using IAopDAL;
using IAopBLL;
using Command;
namespace AopBLL
{
    public class ReadDataBLL:IReadDataBLL
    {
        IReadData bllServer = new UnityContainerHelp().GetServer<IReadData>();
        public string ReadDataStr(string Name)
        {
            throw new Exception("BLL出現異常");
        }
    }
}

3:主程序層(Aopunity)主要關注配置信息

a:首先是Log4Net.config,天天生成一個.txt文件記錄異常內容

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
  </configSections>
  <log4net>
    <appender name="RollingLogRootFileAppender" type="log4net.Appender.RollingFileAppender">
      <!--日誌的路徑-->
      <file value=".\Log\WanLog" />
      <!--是否覆蓋,默認是追加true-->
      <appendToFile value="true"/>
      <!--文件滾動週期(每日建立新日誌文件)-->
      <datePattern value="yyyyMMdd&quot;.txt&quot;"/>
      <!--設置無限備份=-1 ,最大備份數爲1000-->
      <maxSizeRollBackups value="1000"/>
      <!--名稱是否能夠更改成false爲能夠更改-->
      <staticLogFileName value="false" />
      <!--文件滾動選項Composite表示根據日期和大小來滾動-->
      <rollingStyle value="Composite" />
      <layout type="log4net.Layout.PatternLayout">
        <param name="ConversionPattern" value="%d{yyyy-MM-dd HH:mm:ss}[%t][%-5p][%c]%m%n%exception%n" />
      </layout>
    </appender>
    <root>
      <level value="All" />
      <appender-ref ref="RollingLogRootFileAppender" />
    </root>
  </log4net>
</configuration>

b:App.config則是一些依賴注入跟Aop的配置,增長sectionExtension節點引用;interceptor則表示攔截器的類型,interceptionBehavior對應處理程序,lifetime生命週期

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity xmlns="http://schemas.microsoft.com/practces/2010/unity">
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, 

Microsoft.Practices.Unity.Interception.Configuration"/>
    <typeAliases>
      <typeAlias alias="transient" type="Microsoft.Practices.Unity.TransientLifetimeManager, Microsoft.Practices.Unity"/>
    </typeAliases>
    <alias alias="ExceptionLogBehaviorName" type="Command.ExceptionLogBehavior,Command"></alias>
    <container name="FirstClass">
      <extension type="Interception"/>
      <register type="IAopBLL.IReadDataBLL,IAopBLL" mapTo="AopBLL.ReadDataBLL,AopBLL">
        <interceptor type="InterfaceInterceptor"/>
        <interceptionBehavior type="ExceptionLogBehaviorName"/>
        <lifetime type="transient"></lifetime>
      </register>
      <register type="IAopBLL.IPropertyBLL,IAopBLL" mapTo="AopBLL.PropertyBLL,AopBLL"></register>
      <register type="IAopDAL.IReadData,IAopDAL" mapTo="AopOracelDAL.ReadDataDAL,AopOracelDAL"/>
    </container>
  </unity> 
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>

c:主程序運行代碼以下:

using IAopBLL;
using Command;
namespace AopUnity
{
    class Program
    {
        static void Main(string[] args)
        {
            IReadDataBLL bllServer = new UnityContainerHelp().GetServer<IReadDataBLL>();
            Console.WriteLine(bllServer.ReadDataStr("踏浪帥"));
        }
    }
}

 

四:運行效果

 

五:注意事項

1:主程序沒有對Microsoft.Practices.Unity.Interception.Configuration.dll進行引用報錯

建立 unity 的配置節處理程序時出錯: 給定程序集名稱或基本代碼無效。 (異常來自 HRESULT:0x80131047)

<sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, 
Microsoft.Practices.Unity.Interception.Configuration"/>

解決方法:主要是咱們配置文件中有,則要對它進行引用

2:由於咱們把log4net配置文件單獨出來,因此要設置其爲始終複製

 

 

若是,您認爲閱讀這篇博客讓您有些收穫,不妨點擊一下右下角的【推薦】按鈕,如有不足歡迎指正。  由於,個人寫做熱情也離不開您的確定支持。
 
感謝您的閱讀(源代碼下載

相關文章
相關標籤/搜索