F:\开源项目\Dot Net\Castle.NET\Castle-src\Facilities\AspectSharp\AspectSharp.sln
1. ExternalConfigurationTestCase.cs 外部配置测试
using
System;
using
NUnit.Framework;
using
Castle.Model.Configuration;
using
Castle.Windsor;
using
Castle.Facilities.AspectSharp.Tests.Components;
using
Castle.Facilities.AspectSharp.Tests.Interceptors;
///
<summary>
///
Summary description for ExternalConfigurationTestCase.
///
</summary>
[TestFixture]
public
class
ExternalConfigurationTestCase
{
[Test]
public
void
ExternalConfigurationUsage()
{
WindsorContainer container
=
new
WindsorContainer(
"
../aop_castle_config.xml
"
);
container.AddFacility(
"
aspectsharp
"
,
new
AspectSharpFacility() );
//
Logger implementation
container.AddComponent(
"
logger
"
,
typeof
(ILogger),
typeof
(MemoryLogger) );
//
AopAlliance interceptors
container.AddComponent(
"
log4netinterceptor
"
,
typeof
(LoggerTraceInterceptor) );
//
Protocol handlers
container.AddComponent(
"
protocolhandler.miranda
"
,
typeof
(IProtocolHandler),
typeof
(MirandaProtocolHandler) );
container.AddComponent(
"
protocolhandler.messenger
"
,
typeof
(IProtocolHandler),
typeof
(MessengerProtocolHandler) );
//
using
//
ILogger logger = (ILogger) container[ typeof(ILogger) ];
//
Assert.AreEqual( 0, logger.Contents.Length );
IProtocolHandler handler
=
(IProtocolHandler)
container[
"
protocolhandler.miranda
"
];
handler.Handle(
"
contents
"
);
handler
=
(IProtocolHandler) container[
"
protocolhandler.messenger
"
];
handler.Handle(
"
contents
"
);
//
Assert.AreEqual( "Entering Handle Leaving Handle Entering Handle Leaving Handle ",
//
logger.Contents );
}
}
WindsorContainer 产生的 container 是 Castle 的 IoC 容器,用于动态产生类实例或根据接口动态产生类实例。也可以根据键值从容器中取出实例。
IProtocoHandler handler = (IProtocoHandler) container[ "protocolhandler.miranda" ] 这种调用在失败时会产生异常,
IProtocoHandler handler = container[ "protocolhandler.miranda" ] as IProtocoHandler 这种调用在失败时会使 handler 为 null 。
handler 是两个基于 IProtocolHandler 接口的业务级的例程,Handle(string) 是业务逻辑性质的方法体,没有现实的业务意义,只是用于演示。
2. 象征性的业务性质的 handler 例程 MirandaProtocolHandler.cs
using
System;
///
<summary>
///
Summary description for MirandaProtocolHandler.
///
</summary>
public
class
MirandaProtocolHandler : IProtocolHandler
{
public
MirandaProtocolHandler()
{
}
#region
IProtocolHandler Members
public
void
Handle(String contents)
{
Console.WriteLine(
"
MirandaProtocolHandler is handling contents
"
);
}
#endregion
}
MessengerProtocolHandler 与此一模一样,不同的只是 Handle 方法体的输出信息内容把 Miranda 改为 Messenger。
3. 『logger』,MemoryLogger.cs
这是 1. 中向 IoC container 使用 AddComponent 添加的第一个类
using
System;
using
System.Text;
///
<summary>
///
Summary description for MemoryLogger.
///
</summary>
public
class
MemoryLogger : ILogger
{
private
StringBuilder _messages
=
new
StringBuilder();
public
MemoryLogger()
{
}
#region
ILogger Members
public
void
Trace(String content)
{
Console.WriteLine(
"
Tracing
"
+
content
+
"
"
);
}
public
void
Enter(String name)
{
_messages.Append(
"
Entering
"
+
name
+
"
"
);
Console.WriteLine(
"
Entering
"
+
name
+
"
"
);
}
public
void
Leave(String name)
{
_messages.Append(
"
Leaving
"
+
name
+
"
"
);
Console.WriteLine(
"
Leaving
"
+
name
+
"
"
);
}
public
String Contents
{
get
{
return
_messages.ToString(); }
}
#endregion
}
这是测试过程中需要用到的 logger 实例的类声明。实现了 ILogger 接口。
测试用例中只使用了 Enter 和 Leave 两个方法。假设如果成功的话,进入某个方法时会象征性输出日志“Entering....”而结束某方法时会象征性输出日志“Leaving....”
4. 『横切面拦截机』LoggerTraceInterceptor.cs
拦截机是 AOP 的精髓之一,面向方面编程(AOP)意义等同于面向『横切面』编程。在 Castle AspectSharp 的测试用例中展示的都是 AOP 中的 advice 机制,而且都是 around 的,可以自主选择在方法之前还是之后或者两者皆有的地方添加执行横切面性质的额外方法。
using
System;
using
AopAlliance.Intercept;
using
Castle.Facilities.AspectSharp.Tests.Components;
///
<summary>
///
AopAlliance interceptor, however kept within the container
///
</summary>
public
class
LoggerTraceInterceptor : IMethodInterceptor
{
private
ILogger _logger;
public
LoggerTraceInterceptor(ILogger logger)
{
_logger
=
logger;
}
public
object
Invoke(IMethodInvocation invocation)
{
Console.WriteLine(
"
\nLoggerTraceIntercepter stand by \n
"
);
_logger.Enter( invocation.Method.Name );
object
value
=
invocation.Proceed();
_logger.Leave( invocation.Method.Name );
return
value;
}
}
注意
1)
继承了 IMethodInterceptor,告诉 AspectSharp 这是个方法级的拦截机,AspectSharp 还提供了 IConstructoriInterceptor 用于实现针对构造函数的拦截机。
2)这里需要预先注入 logger 实例,
构造式注入
3)object value = invocation.Proceed() 指示执行原本的业务方法
4)在 Invoke 方法体内声明了在执行原本的业务方法之前和之后各记录一条日志(Enter 和 Leave),这也就是拦截机的作用。
5)object value = .... 然后必须做 return value ,这是为了实现正常业务逻辑上的对象返回。当然,如果在 invocation.Proceed() 时产生了异常就不会执行 _logger.Leave 和 return value 了。
6)
注意 LoggerTraceInterceptor 在代码中是有(且需要)显式声明的,在 ExternalConfigurationTestCase.cs 中,这说明使用
拦截机需要『入侵』代码,而下面的 Mixin 混入不需要在代码中声明。
5. 『Mixin(混入)』SecurityMixin.cs
using
AspectSharp.Core;
namespace
Castle.Facilities.AspectSharp.Tests.Components
{
using
System;
///
<summary>
///
Summary description for SecurityMixin.
///
</summary>
public
class
SecurityMixin : IProxyAware
{
public
SecurityMixin()
{
}
public
void
SetProxy(
object
proxy)
{
Console.WriteLine(
"
\nSecurityMixin setting proxy\n
"
);
}
}
}
这个 Mixin 没有出现在 ExternalConfigurationTestCase.cs 代码中,因为它在下面的 aop_castle_config.xml 中声明了,而且在初始化 WindsorContainer IoC 容器时已经载入了这个外部配置文件。
测试输出表明,这个 Mixin 优先于拦截机 Interceptor 执行,且对于每次执行 Handle() 方法仅在最开头时执行一次。
6. 外部配置文件 ..\aop_castle_config.xml
<
configuration
>
<
facilities
>
<
facility
id
="aspectsharp"
>
<![CDATA[
import Castle.Facilities.AspectSharp.Tests.Components in Castle.Facilities.AspectSharp.Tests
import Castle.Facilities.AspectSharp.Tests.Interceptors in Castle.Facilities.AspectSharp.Tests
interceptors [ "key" : LoggerTraceInterceptor ]
mixins [ "key" : SecurityMixin ]
aspect ProtocolHandlerLogger for [ assignableFrom(IProtocolHandler) ]
include "key"
pointcut method(*)
advice("key")
end
end
]]>
</
facility
>
</
facilities
>
</
configuration
>
import .... in .... 完整语法是 import OneNameSpace in OneAssembly 声明了从某个 .NET 程序集中引入命名空间
interceptors [ "key" : LoggerTraceInterceptor ] 声明拦截机,且把 LoggerTraceInterceptor 命名为 "key"
mixins [ "key" : SecurityMixin ] 声明混淆,且把 SecurityMixin 命名为 "key"
aspect ProtocolHandlerLogger 这个只是 aspect 的命名而已,就像类的命名一样
for [ assignableFrom(IProtocolHandler) ] 指示凡实现 IProtocolHandler 接口的类都适用于这个 aspect 过程
如果是 for MirandaProtocolHandler 则是只有 MirandaProtocolHandler 这个类适用于这个 aspect 过程
include "key" 引用之前声明命名为 "key" 的拦截机和混淆
advice("key") 执行名为 "key" 的拦截和混淆,测试输出标明 Mixin 优先于拦截机执行
7. 测试输出
------ Test started: Assembly: Castle.Facilities.AspectSharp.Tests.dll ------
SecurityMixin setting proxy...
LoggerTraceIntercepter stand by ...
Entering Handle
MirandaProtocolHandler is handling contents ...
Leaving Handle
SecurityMixin setting proxy...
LoggerTraceIntercepter stand by ...
Entering Handle
MessengerProtocolHandler is handling contents ...
Leaving Handle
1 passed, 0 failed, 0 skipped, took 1.64 seconds.
Links:
张老三的 Aspect# 文章
http://www.narchitecture.net/Articles/ArticleList.aspx?category=8