完全通过配置实现AOP的资料太少了,今天忙了好几个小时终于走通了,分享一下。
模拟业务是:登陆,记录登陆日志。
// 业务接口 public interface IStudentManage { bool Login(string userId, string userName); } public class StudentManage:IStudentManage { public StudentManage() { } public bool Login(string userId, string userName) { return userId == "123" && userName == "123"; } } /// <summary> /// 登陆日志 /// </summary> public class UserLogCallHandler : ICallHandler { /// <summary> /// 构造函数,此构造函数是用于Attribute调用 /// </summary> /// <param name="message"> 消息 </param> /// <param name="parameterName"> 参数名 </param> public UserLogCallHandler(string message, string parameterName) { this.Message = message; this.ParameterName = parameterName; } public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext) { //检查参数是否存在 if (input == null) throw new ArgumentNullException("input"); if (getNext == null) throw new ArgumentNullException("getNext"); //开始拦截,此处可以根据需求编写具体业务逻辑代码 //调用具体方法 var result = getNext()(input, getNext); // 记录登陆日志 } public string Message { get; set; } public string ParameterName { get; set; } private int order = 0; public int Order { get { return order; } set { order = value; } } }
最关键的XML配置
<configuration> <configSections> <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/> </configSections> <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> <assembly name="UnityAOPConfig"/> <namespace name="UnityAOPConfig"/> <!--新增配置节扩展,用于下面的<interception>配置节--> <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration" /> <container name="LoginContainer"> <!--为容器增加Interception扩展,如不增加下面interception配置会报错--> <extension type="Interception"/> <interception> <!--增加一个名为UserLog的拦截策略,用于记录日志--> <policy name="UserLog"> <!--新增MemberNameMatchingRule匹配规则,同时需要同过配置初始化匹配规则构造函数 具体可查看Unity.InterceptionExtension.PolicyInjection.MatchRule下具体类--> <matchingRule name="rule1" type="MemberNameMatchingRule"> <lifetime type="singleton"/> <constructor> <param name="nameToMatch" value="Login"/> </constructor> </matchingRule> <!--增加调用处理程序,这边指定的是我自定义的UserLogCallHandler--> <!--同样也需要初始化构造函数--> <callHandler name="handler1" type="UserLogCallHandler"> <lifetime type="singleton"/> <constructor> <param name="message" type="System.String" value="登录成功!"> </param> <param name="parameterName" type="System.String" value=" "> </param> </constructor> </callHandler> </policy> </interception> <!--注册对象关系,需要注意的是需要为这个注册增加TransparentProxyInterceptor的拦截器--> <register type="IStudentManage" mapTo="StudentManage"> <interceptor type="TransparentProxyInterceptor" /> <interceptionBehavior type="PolicyInjectionBehavior" /> </register> </container> </unity> </configuration>
前台调用代码
public static IUnityContainer GetIUnityContainer(string nodeName) { //根据文件名获取指定config文件 var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = "Web.config" }; //从config文件中读取配置信息 Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None); var unitySection = (UnityConfigurationSection)configuration.GetSection("unity"); var container = new UnityContainer().LoadConfiguration(unitySection, nodeName); return container; } protected void btnSubmit_Click(object sender, EventArgs e) { IUnityContainer container = new UnityContainer().LoadConfiguration("LoginContainer"); IStudentManage studentBll = container.Resolve<IStudentManage>(); if (studentBll.Login(txtUid.Text.Trim(), txtPwd.Text.Trim())) { if (string.IsNullOrEmpty(Request.QueryString["returnUrl"]) == false) { Response.Redirect(Request.QueryString["returnUrl"]); } else { Response.Redirect("~/Default.aspx"); } } else { ltMsg.Text = "用户名或密码不正确,请重试!"; } } }