AOP面向方面编程---postsharp
PostSharp是一个用于在.NET平台上实现AOP(Aspect-Oriented Programming,面向方面编程)的框架,现通过简单的示例代码来演示如何使用postsharp。
1、新建一个控制台应用程序。.net框架是4.6.1版本的。
2、创建一个类CoreBusiness,表示用于完成项目的核心业务。
class CoreBusiness
{
[Log(ActionName = "Work_1")]
public void Work_1()
{
Console.WriteLine("执行Work_1核心业务");
}
}
3、在Program中调用CoreBusiness的对象来完成业务功能。
class Program
{
static CoreBusiness cb = new CoreBusiness();
static void Main(string[] args)
{
cb.Work_1(); Console.Read();
}
}
4、假设现在项目已经开发完成了。但是现在要求给项目添加日志,记录每个核心业务的执行情况。按照以前的老办法(不用筛选器的情况下),需要定义一个日志操作类:
class LoggingHelper
{
public static void Writelog(String message)
{
Console.WriteLine(message);
}
}
然后在需要记录日志的地方,实例化LoggingHelper的对象,然后写入日志。这样一来,就必须对原来已经开发的项目进行修改,这就违反了开闭原则了。而且添加日志并不是业务的需求变动,不应该去修改业务项目。
5、现在通过AOP面向方面的编程思想来解决这个日志的问题。要实现AOP,有很多框架,比如:Encase ,NKalore,PostSharp,AspectDNG,SetPoint等等。现在通过PostSharp来演示一下。
6、要使用PostSharp,首先必须要安装它,在NuGet中收索PostSharp,安装的是6.0.27版本的,这个版本只有45天的试用期
7、定义一个LogAttribute类,继承OnMethodBoundaryAspect,这个Aspect提供了进入、退出函数等连接点方法。另外,Aspect上必须设置“[Serializable] ”,这与PostSharp内部对Aspect的生命周期管理有关
[Serializable]
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class LogAttribute : OnMethodBoundaryAspect
{
public string ActionName { get; set; }
public override void OnEntry(MethodExecutionArgs eventArgs)
{
LoggingHelper.Writelog(ActionName + "开始执行");
} public override void OnExit(MethodExecutionArgs eventArgs)
{
LoggingHelper.Writelog(ActionName + "成功完成");
} }
8、然后Log特性应用到Work_1函数,这个也可以应用到类上面,如果要应用到类,在定义LogAttribute的时候,AttributeUsage属性的值就需要添加一个AttributeTargets.class
整个程序唯一修改的也就这里了。然后运行程序
这样就完成了日志的添加功能。
9、现在有这样一个需求,有个带参数的函数,希望在记录日志的时候,将这个函数的参数及参数值也记录下来。如下图,在记录日志的时候,需要知道调用Work_2时,具体传入的参数值。
要实现这个功能,需要修改LogAttribute的OnEntry函数:
public override void OnEntry(MethodExecutionArgs eventArgs)
{
Arguments arguments = eventArgs.Arguments;
StringBuilder sb = new StringBuilder();
ParameterInfo[] parameters = eventArgs.Method.GetParameters();
for (int i = ; arguments != null && i < arguments.Count; i++)
{//进入的参数的值
sb.Append( parameters[i].Name + "=" + arguments[i] + ";");
}
LoggingHelper.Writelog(ActionName + "开始执行");
LoggingHelper.Writelog(ActionName + "的参数:" + sb.ToString());
}
运行后:
10、现在有一个有返回值的函数,要求在日志中记录这个函数的返回结果:
public override void OnExit(MethodExecutionArgs eventArgs)
{
string name = eventArgs.Method.Name;//用这种方式也能获取特性修饰的函数的名称
string value = eventArgs.ReturnValue.ToString();
LoggingHelper.Writelog(name + "的返回值:"+value); LoggingHelper.Writelog(ActionName + "成功完成");
}
运行后:
如果返回结果不是字符串,而是一个类对象,那么eventArgs.ReturnValue就是那个返回的对象,至于怎么将这个对象序列化,这里就不用说了。
比如我定义一个类:
class Modelsf
{
public string name { set; get; }
public string IdNo { set; get; }
}
添加一个核心业务函数:
[Log(ActionName = "Work_4")]
public Modelsf Work_4(Modelsf m)
{
m.name = m.name + "FFFF";
return m;
}
运行程序后的结果:
所以,对于参数和返回值不是基本类型的函数,如果要记录参数和返回值的详细信息,还需要特殊处理。
PostSharp与ActionFilterAttribute的比较
通过上面的示例可以看出postsharp与筛选器很类似。但是筛选器似乎只能用于web项目,不能用在控制台和winform项目,因为这两种项目中无法添加System.Web.Mvc的引用。至于其他项目比如webservice,wcf,webapi能不能用,这个没有
去求证。但是postsharp是可以用在这些项目的。因此postsharp比筛选器的应用范围广。
在web项目中自定义一个action筛选器,继承ActionFilterAttribute。然后在OnActionExecuted和OnActionExecuting这两个函数中添加日志记录。这点和postsharp是一样的。
public class LoggingHelper
{
public static void Writelog(String message)
{
Debug.WriteLine(message);
}
} public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
LoggingHelper.Writelog(filterContext.ActionDescriptor.ActionName + "结束执行");
} public override void OnActionExecuting(ActionExecutingContext filterContext)
{
LoggingHelper.Writelog(filterContext.ActionDescriptor.ActionName+ "开始执行");
}
}
这个MyActionFilter可以直接放到控制器上,不需要像postsharp那样需要专门设置AttributeTargets.class。
对于有参数和返回值的函数,在筛选器中记录日志:
public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Result.GetType().Name == "ContentResult")
{//只有当函数返回的结果是字符串的时候,这种处理方式才能看到返回的内容。如果是其他类型,比如Dictionary<string, string>,都
//没法获得返回的具体内容
ContentResult res = (ContentResult)filterContext.Result;
LoggingHelper.Writelog(filterContext.ActionDescriptor.ActionName + "的返回结果:" + res.Content);
} LoggingHelper.Writelog(filterContext.ActionDescriptor.ActionName + "结束执行"); } public override void OnActionExecuting(ActionExecutingContext filterContext)
{
StringBuilder sb = new StringBuilder();
foreach (var key in filterContext.ActionParameters.Keys)
{
sb.Append(key + "=" + filterContext.ActionParameters[key] + ";");
}
LoggingHelper.Writelog(filterContext.ActionDescriptor.ActionName + "的参数:"+sb.ToString());
LoggingHelper.Writelog(filterContext.ActionDescriptor.ActionName+ "开始执行");
}
}
上面的web项目中没法获取返回值为string以外的函数的返回值,这是因为OnActionExecuted的参数没法获取返回值。下面在webapi里面试试。因为webapi和web项目中的ActionFilterAttribute是处于不同命名空间的,所以其OnActionExecuting和OnActionExecuted
函数的参数类型也就不同。
还是老规矩,在webapi中定义筛选器,代码如下,在webapi中ActionFilterAttribute位于System.Web.Http.Filters空间,而web项目中的ActionFilterAttribute位于System.Web.Mvc。而且复写的两个函数的参数类型也是不同的。
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Web.Http.Controllers;
//using System.Web.Mvc;
using System.Web.Http.Filters; namespace WebApi.Loger
{
public class LoggingHelper
{
public static void Writelog(String message)
{
Debug.WriteLine(message);
}
}
public class MyActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
StringBuilder sb = new StringBuilder();
foreach (var key in actionContext.ActionArguments.Keys)
{
sb.Append(key + "=" + actionContext.ActionArguments[key] + ";");
}
LoggingHelper.Writelog(actionContext.ActionDescriptor.ActionName + "的参数:" + sb.ToString());
LoggingHelper.Writelog(actionContext.ActionDescriptor.ActionName + "开始执行");
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) {
string result = actionExecutedContext.Response.Content.ReadAsStringAsync().Result;
var d = JsonConvert.DeserializeObject<Dictionary<string, string>>(result);
LoggingHelper.Writelog(actionExecutedContext.ActionContext.ActionDescriptor.ActionName + "执行结果"+result);
LoggingHelper.Writelog(actionExecutedContext.ActionContext.ActionDescriptor.ActionName + "结束执行");
}
} public class User
{
public string Name { set; get; }
public string Idno { set; get; }
}
}
在webapi的value控制器中添加3个函数:
public HttpResponseMessage GetInfo(string name,string idno)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
HttpResponseMessage result = new HttpResponseMessage {
Content = new StringContent(serializer.Serialize(name + "###" + idno), Encoding.GetEncoding("UTF-8"), "application/json")
};
return result;
}
public HttpResponseMessage GetInfos(string name,string idno)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
string str = serializer.Serialize(new Dictionary<string, string>() { { name, idno } ,{ "abc",""} });
HttpResponseMessage result = new HttpResponseMessage {
Content = new StringContent(str, Encoding.GetEncoding("UTF-8"), "application/json") };
return result;
}
public HttpResponseMessage GetUser(string name,string idno)
{
User u = new User() { Name = name, Idno = idno };
JavaScriptSerializer serializer = new JavaScriptSerializer();
string str = serializer.Serialize(u);
HttpResponseMessage result = new HttpResponseMessage
{
Content = new StringContent(str, Encoding.GetEncoding("UTF-8"), "application/json")
};
return result;
}
因为webapi默认返回的数据到了客户端是xml格式的,所以通过代码中的处理,将其返回的数据先序列化放到HttpResponseMessage,然后在筛选器中再反序列化。
注意,下图中的反序列化的语句,这个要根据webapi返回的内容的类型来具体指定反序列化的类型。但是result肯定是一个json字符串。
用这种方式,可以获取函数返回的字符串或者其他类对象的数据。当然可能还有其他的返回数据的方式,这里主要是证明在筛选器中,可以获得函数的返回值这个事实。
AOP面向方面编程---postsharp的更多相关文章
- 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存
代码已上传Github+Gitee,文末有地址 上回<从壹开始前后端分离[ .NET Core2.0 Api + Vue 2.0 + AOP + 分布式]框架之九 || 依赖注入IoC学习 + ...
- Z从壹开始前后端分离【 .NET Core2.0/3.0 +Vue2.0 】框架之十 || AOP面向切面编程浅解析:简单日志记录 + 服务切面缓存
本文梯子 本文3.0版本文章 代码已上传Github+Gitee,文末有地址 大神反馈: 零.今天完成的深红色部分 一.AOP 之 实现日志记录(服务层) 1.定义服务接口与实现类 2.在API层中添 ...
- AOP 面向切面编程, Attribute在项目中的应用
一.AOP(面向切面编程)简介 在我们平时的开发中,我们一般都是面对对象编程,面向对象的特点是继承.多态和封装,我们的业务逻辑代码主要是写在这一个个的类中,但我们在实现业务的同时,难免也到多个重复的操 ...
- AOP面向切面编程的四种实现
一.AOP(面向切面编程)的四种实现分别为最原始的经典AOP.代理工厂bean(ProxyFacteryBean)和默认自动代理DefaultAdvisorAutoProxyCreator以及Bea ...
- Javascript aop(面向切面编程)之around(环绕)
Aop又叫面向切面编程,其中“通知”是切面的具体实现,分为before(前置通知).after(后置通知).around(环绕通知),用过spring的同学肯定对它非常熟悉,而在js中,AOP是一个被 ...
- Method Swizzling和AOP(面向切面编程)实践
Method Swizzling和AOP(面向切面编程)实践 参考: http://www.cocoachina.com/ios/20150120/10959.html 上一篇介绍了 Objectiv ...
- [转] AOP面向切面编程
AOP面向切面编程 AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术. ...
- C# AOP 面向切面编程之 调用拦截
有时候我们需要在代码中对方法调用进行拦截,并修改参数和返回值,这种操作叫做AOP(面向切面编程) 不过需要注意的是,AOP的效率很慢,在需要高效率场合慎用. 以下是C#的AOP方法: 首先建立一个控制 ...
- 【原创】Android AOP面向切面编程AspectJ
一.背景: 在项目开发中,对 App 客户端重构后,发现用于统计用户行为的友盟统计代码和用户行为日志记录代码分散在各业务模块中,比如在视频模块,要想实现对用户对监控点的实时预览和远程回放行为进行统计, ...
随机推荐
- 建造高塔(codevs 1689)
题目描述 Description n有n种石块,石块能无限供应.每种石块都是长方体,其中第i种石块的长.宽.高分别为li.wi.hi.石块可以旋转,使得其中两维成为长度和宽度,第三维成为高度.如果要把 ...
- 【NOIP2017练习】论战大原题(并查集)
题意:给定一个n个点m条边的无向图.定义一条路径的长度为路径上最小边的权值. 定义dist(i,j)为起点为i,终点为j的长度最长的路径的长度.求出第k大的dist(i,j)(i<j). 对于所 ...
- 利用mysql分析小规模数据
1 获取数据 示例:(/home/work/data/1.data) 123457,chenli,70 123458,liuyang,71 2 create table CREATE TABLE sc ...
- HDU 5644 King's Pliot【费用流】
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5644 题意: 每天都有p[i]个飞行员进行阅兵,飞行员只工作一天. m个休假公式,花费tt[i]元让 ...
- jquery控制Request Payload和Form Data
Request Payload方式,会发起两次请求 Form Data只发起一次请求 若要把一个ajax请求改为Payload方式,设置contentType即可,发现请求参数不是对象,再把参数转换为 ...
- P1334 瑞瑞的木板 洛谷
https://www.luogu.org/problem/show?pid=1334 题目描述 瑞瑞想要亲自修复在他的一个小牧场周围的围栏.他测量栅栏并发现他需要N(1≤N≤20,000)根木板,每 ...
- operamasks—omGrid/omBorderLayout的混合使用
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="test.aspx.cs&q ...
- Linux系统备份还原工具4(rsync/远程数据同步工具)
rsync即是能备份系统也是数据同步的工具. 在Jenkins上可以使用rsync结合SSH的免密登录做数据同步和分发.这样一来可以达到部署全命令化,不需要依赖任何插件去实现. 命令参考:http:/ ...
- Servlet的调试
以下内容引用自http://wiki.jikexueyuan.com/project/servlet/debugging.html: 测试/调试Servlet始终是困难的.Servlets往往涉及大量 ...
- laravel toggle方法
toggle方法主要用于多对多关系中,attach detach 比如点赞 收藏 1.user表 2.post表 title content 3.中间表 favoriate user_id post_ ...