首先声明,Enterprise Library
v5.0业已宣告了,此处的DEMO是基于Enterprise Library v4.1者版本.
差别并无极端多矣.Enterprise Library
提供了图的成为布局工具,让我们无去描绘XML的布文件.我们好为此policy
injection application
block和Unity搭建筑一个简单易行的AOP框架,而你不用写一句代码.
AOP框架解决是兑现Logger,Transaction,同步处理,权限决定,验证等职能的复用,让我们拿再多的生机关注在工作达到.

         使用安排工具分别增加Exception Handing Application Block,Logging
Application Block, Policy Injection Application Block如下图:

图片 1

       PIAB的Matching
Rules是非常利索的,可以兼容一个Type,Namespace,Assembly等.这里配置的凡Tag
Attribute,当然还好安排由定义规则.为PIAB的Handlers增加Exception
Handling,Logging,TransactionScope
handler,注意是TransactionScope是社区贡献的,去Enterprise Library
Contrib project下载.
这里而或还注意到端的Exception Handing Application
Block也有一个Logging Handler, 不是暨一个,但它可共享Logging
Application Block的Category.配置时是非常灵活的.最终的XML是:

  <configSections>

    <section name="policyInjection" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.Configuration.PolicyInjectionSettings, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

    <section name="loggingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.LoggingSettings, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

    <section name="exceptionHandling" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

    <section name="dataConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Data.Configuration.DatabaseSettings, Microsoft.Practices.EnterpriseLibrary.Data, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />

  </configSections>

  <policyInjection>

    <policies>

      <add name="MyPIPolicy">

        <matchingRules>

          <add match="MyTagName" ignoreCase="false" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.MatchingRules.TagAttributeMatchingRule, Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

            name="Tag Attribute Matching Rule" />

        </matchingRules>

        <handlers>

          <add exceptionPolicyName="MyPolicy" order="2" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers.ExceptionCallHandler, Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

            name="Exception Handling Handler" />

          <add logBehavior="BeforeAndAfter" beforeMessage="MyDefault Before"

            afterMessage="MyDefault After&#xD;&#xA;" eventId="0" includeParameterValues="true"

            includeCallStack="true" includeCallTime="true" priority="-1"

            severity="Information" order="0" type="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers.LogCallHandler, Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

            name="Logging Handler">

            <categories>

              <add name="General" />

            </categories>

          </add>

          <add transactionScopeOption="Required" timeout="00:01:00" isolationLevel="Serializable"

            interopOption="None" complete="true" type="EntLibContrib.PolicyInjection.CallHandlers.TransactionScopeCallHandler, EntLibContrib.PolicyInjection.CallHandlers, Version=4.1.0.0, Culture=neutral, PublicKeyToken=null"

            name="TransactionScope Handler" />

        </handlers>

      </add>

    </policies>

  </policyInjection>

  <loggingConfiguration name="Logging Application Block" tracingEnabled="true"

    defaultCategory="General" logWarningsWhenNoCategoriesMatch="true">

    <listeners>

      <add fileName="Generaltrace.log" header="----------------------------------------"

        footer="----------------------------------------" formatter="Text Formatter"

        listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.FlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

        traceOutputOptions="None" filter="All" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.FlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

        name="FlatFile TraceListener" />

      <add fileName="ErrorRolling.log" footer="----------------------------------------"

        formatter="" header="----------------------------------------"

        rollFileExistsBehavior="Overwrite" rollInterval="None" rollSizeKB="0"

        timeStampPattern="yyyy-MM-dd" listenerDataType="Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.RollingFlatFileTraceListenerData, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

        traceOutputOptions="None" filter="All" type="Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.RollingFlatFileTraceListener, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

        name="Rolling Flat File Trace Listener" />

    </listeners>

    <formatters>

      <add template="Timestamp: {timestamp}&#xD;&#xA;Message: {message}&#xD;&#xA;Category: {category}&#xD;&#xA;Priority: {priority}&#xD;&#xA;EventId: {eventid}&#xD;&#xA;Severity: {severity}&#xD;&#xA;Title:{title}&#xD;&#xA;Machine: {machine}&#xD;&#xA;Application Domain: {appDomain}&#xD;&#xA;Process Id: {processId}&#xD;&#xA;Process Name: {processName}&#xD;&#xA;Win32 Thread Id: {win32ThreadId}&#xD;&#xA;Thread Name: {threadName}&#xD;&#xA;Extended Properties: {dictionary({key} - {value}&#xD;&#xA;)}"

        type="Microsoft.Practices.EnterpriseLibrary.Logging.Formatters.TextFormatter, Microsoft.Practices.EnterpriseLibrary.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

        name="Text Formatter" />

    </formatters>

    <categorySources>

      <add switchValue="All" name="ExceptionLogger">

        <listeners>

          <add name="Rolling Flat File Trace Listener" />

        </listeners>

      </add>

      <add switchValue="All" name="General">

        <listeners>

          <add name="FlatFile TraceListener" />

        </listeners>

      </add>

    </categorySources>

    <specialSources>

      <allEvents switchValue="All" name="All Events" />

      <notProcessed switchValue="All" name="Unprocessed Category" />

      <errors switchValue="All" name="Logging Errors &amp; Warnings">

        <listeners>

          <add name="Rolling Flat File Trace Listener" />

        </listeners>

      </errors>

    </specialSources>

  </loggingConfiguration>

  <exceptionHandling>

    <exceptionPolicies>

      <add name="MyPolicy">

        <exceptionTypes>

          <add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"

            postHandlingAction="NotifyRethrow" name="Exception">

            <exceptionHandlers>

              <add logCategory="ExceptionLogger" eventId="100" severity="Error"

                title="Enterprise Library Exception Handling" formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

                priority="0" useDefaultLogger="false" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"

                name="Logging Handler" />

            </exceptionHandlers>

          </add>

        </exceptionTypes>

      </add>

    </exceptionPolicies>

  </exceptionHandling>

亟待引用以下顺序集:

   1:    <Reference Include="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />

   2:      <Reference Include="Microsoft.Practices.EnterpriseLibrary.PolicyInjection, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />

   3:      <Reference Include="Microsoft.Practices.EnterpriseLibrary.PolicyInjection.CallHandlers, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />

   4:      <Reference Include="Microsoft.Practices.Unity, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />

   5:      <Reference Include="Microsoft.Practices.Unity.Interception, Version=1.2.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />

   6:     <Reference Include="EntLibContrib.PolicyInjection.CallHandlers, Version=4.1.0.0, Culture=neutral, processorArchitecture=MSIL">

哼了,一切就是绪了. 让咱来测试下:

   1:      public interface IProdutDAO 

   2:      {

   3:          bool AddProduct(string productname);

   4:          bool DeleteProduct(int pkid);

   5:          bool UpdateProduct(int pkid);

   6:      }

   7:   

   8:     /// <summary>

   9:      /// ProductDAO

  10:      /// </summary>

  11:      /// <remarks>author: Petter Liu http://wintersun.cnblogs.com </remarks>

  12:      public class ProductDAO : IProdutDAO

  13:      {

  14:         [ExceptionCallHandler("MyPolicy")]

  15:          public bool AddProduct(string productname)

  16:          {

  17:              throw new Exception("You can not create duplicate user in system");

  18:          }

  19:   

  20:          [LogCallHandler]

  21:         public bool DeleteProduct(int pkid)

  22:         {

  23:             return true;

  24:         }

  25:   

  26:          [TransactionScopeCallHandler]

  27:          [ExceptionCallHandler("MyPolicy")]

  28:          public bool UpdateProduct(int pkid)

  29:          {

  30:              string sql = @"delete Employees where EmployeeID=(select max(EmployeeID) from Employees where LastName='Petter')

  31:                                 Insert into Employees(LastName,FirstName,Title) values('testname','asddddddddddddddddddddddasdfasdffsd','fsfs');";

  32:   

  33:              ConnectionStringSettings cfg = ConfigurationManager.ConnectionStrings["maindb"];

  34:              DbProviderFactory factory = DbProviderFactories.GetFactory(cfg.ProviderName);

  35:             

  36:              using (DbConnection cnx = factory.CreateConnection())

  37:              {

  38:                  using (DbCommand cmd = factory.CreateCommand())

  39:                  {

  40:                      cnx.ConnectionString = cfg.ConnectionString;

  41:                      cmd.Connection = cnx;

  42:                      cmd.CommandText = sql;

  43:             

  44:                      cnx.Open();

  45:                      int roweffect = cmd.ExecuteNonQuery();

  46:                      cnx.Close();

  47:                      cmd.Dispose();

  48:                  }

  49:              }

  50:              return false;

  51:          }

  52:      }

此地以是Attribute, 看下使用Tag attribute的:

   1:      /// <summary>

   2:      /// All method will be blocked

   3:      /// </summary>

   4:      [Tag("MyTagName")]

   5:      public class ProductLogDAO : IProdutDAO

   6:      {

   7:          public bool AddProduct(string productname)

   8:          {

   9:              throw new Exception("You can not create duplicate user in system");

  10:          }

  11:   

  12:          #region IProdutDAO Members

  13:   

  14:          public bool DeleteProduct(int pkid)

  15:          {

  16:              return true;

  17:          }

  18:   

  19:          #endregion

  20:   

  21:          #region IProdutDAO Members

  22:   

  23:          public bool UpdateProduct(int pkid)

  24:          {

  25:              return false;

  26:          }

  27:   

  28:          #endregion

  29:      }

我们的UnitTest Code如下:

   1:      /// <summary>

   2:      /// TestPIAB

   3:      /// </summary>

   4:      /// <remarks>Author Petter Liu http://www.cnblogs.com/wintersun </remarks>

   5:      [TestFixture]

   6:      public class TestPIAB

   7:      {

   8:          [Test]

   9:          [ExpectedException(typeof(Exception))]

  10:          public void TestThrowException()

  11:          {

  12:              IProdutDAO productdao = PolicyInjection.Create<ProductDAO, IProdutDAO>();

  13:              productdao

  14:                  .AddProduct("new product");

  15:   

  16:          }

  17:   

  18:          [Test]

  19:          public void TestAutoLogger()

  20:          {

  21:              IProdutDAO productdao = PolicyInjection.Create<ProductDAO, IProdutDAO>();

  22:              productdao.DeleteProduct(1);

  23:   

  24:          }

  25:   

  26:          [Test]

  27:          public void TestAutoTransaction()

  28:          {

  29:              IProdutDAO productdao = PolicyInjection.Create<ProductDAO, IProdutDAO>();

  30:              productdao.UpdateProduct(1);

  31:          }

  32:   

  33:          [Test]

  34:          [ExpectedException(typeof(Exception))]

  35:          public void TestTagAttribute()

  36:          {

  37:              IProdutDAO productdao = PolicyInjection.Create<ProductLogDAO, IProdutDAO>();

  38:              productdao

  39:                  .AddProduct("new product");

  40:           

  41:          }

  42:   

  43:          [Test]

  44:          [ExpectedException(typeof(Exception))]

  45:          public void TestWorkingWithUntiy()

  46:          {

  47:              IUnityContainer container = new UnityContainer();

  48:              container.RegisterType<IProdutDAO, ProductDAO>();

  49:              container.AddNewExtension<Interception>();

  50:              container.Configure<Interception>().SetDefaultInterceptorFor(typeof(IProdutDAO)

  51:                  , new TransparentProxyInterceptor());

  52:              var productdao = container.Resolve<IProdutDAO>();

  53:              productdao

  54:                .AddProduct("new product");

  55:          }

  56:      }

当我们尽第一只AddProduct时, 将会有这样的日志ErrorRolling.log,
这是自动Exception Logging:

----------------------------------------
ExceptionLogger Error: 100 : Timestamp: 2010-06-07 14:14:54
Message: HandlingInstanceID: d684dfc6-0e5a-476d-861f-9c685b818ad3
An exception of type 'System.Exception' occurred and was caught.
----------------------------------------------------------------
06/07/2010 22:14:54
Type : System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Message : You can not create duplicate user in system
Source : WindowsFormsApplication1
Help link : 
Data : System.Collections.ListDictionaryInternal
TargetSite : Boolean AddProduct(System.String)
Stack Trace :    at WindowsFormsApplication1.ProductDAO.AddProduct(String productname) in H:\My Project\DotNet30\WindowsFormsTDD2008\TestPIAB.cs:line 113

Additional Info:

MachineName : USER
TimeStamp : 2010-06-07 14:14:54
FullName : Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
AppDomainName : domain-nunit.addin.dll
ThreadIdentity : 
WindowsIdentity : USER\Petter

Category: ExceptionLogger
Priority: 0
EventId: 100
Severity: Error
Title:Enterprise Library Exception Handling
Machine: USER
App Domain: domain-nunit.addin.dll
ProcessId: 6076
Process Name: D:\Program Files\TestDriven.NET 2.0\ProcessInvocation.exe
Thread Name: TestRunnerThread
Win32 ThreadId:2176
Extended Properties: 
----------------------------------------

当我们实施DeleteProduct, 测试的凡自行智Logging,
此处将转日志文件:Generaltrace.log,有BeforeMessage,AfterMessage,所以来少数截
借这思路,我们好实现前方法,后措施,以后来时空讨论.内容如下:

----------------------------------------
Timestamp: 2010-06-07 14:22:10
Message: 
Category: General
Priority: -1
EventId: 0
Severity: Information
Title:Call Logging
Machine: USER
Application Domain: domain-nunit.addin.dll
Process Id: 6076
Process Name: D:\Program Files\TestDriven.NET 2.0\ProcessInvocation.exe
Win32 Thread Id: 6412
Thread Name: TestRunnerThread
Extended Properties: pkid - 1

----------------------------------------
----------------------------------------
Timestamp: 2010-06-07 14:22:10
Message: 
Category: General
Priority: -1
EventId: 0
Severity: Information
Title:Call Logging
Machine: USER
Application Domain: domain-nunit.addin.dll
Process Id: 6076
Process Name: D:\Program Files\TestDriven.NET 2.0\ProcessInvocation.exe
Win32 Thread Id: 6412
Thread Name: TestRunnerThread
Extended Properties: pkid - 1

----------------------------------------

当我们执行测试UpdateProduct时,这时测试的是自动Transaction,我们故意执行SQL时,先删除一条记录,再插入一条记录,
并造成字段截段的Exception,看以下日志的结果:

ExceptionLogger Error: 100 : Timestamp: 2010-06-07 14:22:03
Message: HandlingInstanceID: 59690aa2-8e07-4bdb-bcfc-28379961e667
An exception of type 'System.Data.SqlClient.SqlException' occurred and was caught.
----------------------------------------------------------------------------------
06/07/2010 22:22:03
Type : System.Data.SqlClient.SqlException, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Message : 将截断字符串或二进制数据。
语句已终止。
Source : .Net SqlClient Data Provider
Help link : 
Errors : System.Data.SqlClient.SqlErrorCollection
Class : 16
LineNumber : 2
Number : 8152
Procedure : 
Server : .\sqlexpress2008
State : 4
ErrorCode : -2146232060
Data : System.Collections.ListDictionaryInternal
TargetSite : Void OnError(System.Data.SqlClient.SqlException, Boolean)
Stack Trace :    at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj)
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlCommand.RunExecuteNonQueryTds(String methodName, Boolean async)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at WindowsFormsApplication1.ProductDAO.UpdateProduct(Int32 pkid) in H:\My Project\DotNet30\WindowsFormsTDD2008\TestPIAB.cs:line 141

Additional Info:

MachineName : USER
TimeStamp : 2010-06-07 14:22:03
FullName : Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
AppDomainName : domain-nunit.addin.dll
ThreadIdentity : 
WindowsIdentity : USER\Petter

Category: ExceptionLogger
Priority: 0
EventId: 100
Severity: Error
Title:Enterprise Library Exception Handling
Machine: USER
App Domain: domain-nunit.addin.dll
ProcessId: 6076
Process Name: D:\Program Files\TestDriven.NET 2.0\ProcessInvocation.exe
Thread Name: TestRunnerThread
Win32 ThreadId:7532
Extended Properties: HelpLink.ProdName - Microsoft SQL Server
HelpLink.ProdVer - 10.00.1600
HelpLink.EvtSrc - MSSQLServer
HelpLink.EvtID - 8152
HelpLink.BaseHelpUrl - http://go.microsoft.com/fwlink
HelpLink.LinkId - 20476

----------------------------------------

是不是相当详细的,记录的内容模板你是可以修改的,这里全部用的是默认的配置值.

TestTagAttribute 这里使用是Tag Attribute,那被标记的对像将按配置的Order值执行所有Injection Handler. 

以最后一个UnitTest方法是PIAB与Unity组合使用.

 

总结,现在是组件开发的时代了,上面所有组件你都可以使用其它的,或是你自己写的,或是第三方的.使用Enterprise Libary各个组件,我们可以轻易搭建一个AOP框架.

作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
正文版权归作者和博客园共有,欢迎转载,但未经作者同意要保留这个段子声明,且以文章页面明显位置被起原文连接,否则保留追究法律责任的权利。
拖欠篇也罢还要披露以自己的独自博客中-Petter Liu
Blog。

相关文章

网站地图xml地图