--自定义属性匹配来拦截方法
面向切面关注将代码的业务流程和其他辅助流程分开解耦和,使我们写业务代码时不再关注之外的逻辑,比如定义一个人(person),具有咆哮的行为(Shout),有时候为了调试跟踪实现而输出一些内容,如下:
public interface PersonBase
{
voidShout(string aa);
}
public class Person : PersonBase
{
public void Shout(string aa)
{
//这句是为了跟踪代码执行情况不属于业务逻辑-
Console.WriteLine("Come Here,pre shout");
//这句是真正的业务逻辑-
Console.WriteLine(aa);
//这句也是为了跟踪代码执行情况
Console.WriteLine("Come Here,post shout");
}
}
可以看出,咆哮方法执行的实际内容只有一条,但是为了跟踪调试而带来了3条代码,而多余的代码是硬写的代码(我们经常会在日志,异常,验证)等代码里附加一些不雅观的代码(感觉不影响业务逻辑,就稍微偷懒点),这样的代码很影响整体的复用,是将来维护系统的杀手。
我希望将跟踪的代码放到方法外面,那么就可以使用方法拦截(AOP),下面开始动手。
注意:需要引用的程序集如下
MicroSoft.Practices.EnterpriseLibra.Common
MicroSoft.Practices.EnterpriseLibra.Common
MicroSoft.Practices.EnterpriseLibra.Common
MicroSoft.Practices.EnterpriseLibra.Common
System.Configuration
首先要解决的第一个问题就是,定位要拦截方法,这就牵扯到匹配方法,这里为了学习,采用自定义属性的方式匹配。
定义一个属性类
[AttributeUsage(AttributeTargets.Method)]
public class TraceAttribute:System.Attribute
{
}
为接口的Shout方法添加该属性
public interface IPerson
{
[Trace]
voidShout(string aa);
}
修改Person的实现
public class Person : IPerson
{
public void Shout(string aa)
{
Console.WriteLine(aa);
}
}
然后修改AppConfig配置文件,使用配置工具配置如下
这表示要拦截定义了TraceAttribute属性的方法。
第二步,方法拦截到了,现在的事情是要注入操作,定义一个用于拦截的类
[ConfigurationElementType(typeof(CustomCallHandlerData))]
public class TraceCallHandler: ICallHandler
{
public string PreMessage { get;privateset; }
public string PostMessage { get;privateset; }
//这个构造函数供配置系统使用(由配置文件自动调用)
publicTraceCallHandler(System.Collections.Specialized.NameValueCollectionattributes)
{
this.PreMessage= String.IsNullOrEmpty(attributes["PreMessage"]) ?"" : attributes["PreMessage"];
this.PostMessage= String.IsNullOrEmpty(attributes["PostMessage"]) ?"" : attributes["PostMessage"];
}
public IMethodReturn Invoke(IMethodInvocationinput,GetNextHandlerDelegate getNext)
{
if (input ==null)thrownewArgumentNullException("input");
if(getNext == null) thrownewArgumentNullException("getNext");
//这句是跟踪输出
Console.WriteLine(PreMessage,System.Threading.Thread.CurrentPrincipal.Identity.Name,input.MethodBase.Name);
//这句是用来调用真正的业务方法
varresult = getNext()(input, getNext);
//这句也是跟踪输出
Console.WriteLine(PostMessage,input.MethodBase.Name);
returnresult;
}
public int Order{get;set;}
}
修改appconfig文件
好了,在Main里测试一下
IPerson per =Microsoft.Practices.EnterpriseLibrary.PolicyInjection.PolicyInjection.Create<Person,IPerson>();
per.Shout("Helloworld ! Come ......");
输出如下
用户[]试图执行[Shout]......
Hello world ! Come ......
[Shout]执行完毕......
可以看到,执行成功。