.NET利用ActionFilter特性记录日志或者运行性能计数器。(log trace or perform perfcounter by actionFilter attribute)...
.NET mvc 中ActionFilter特性可以再在一个Request进入Controller之前,直到View的数据绑定之前都可以触发,它主要包含以下四个方法:
OnActionExecuted |
Called by the ASP.NET MVC framework after the action method executes. (request进入controller,并且执行结束时触发,) |
OnActionExecuting |
Called by the ASP.NET MVC framework before the action method executes. (request尚未进入controller触发,) |
OnResultExecuted |
Called by the ASP.NET MVC framework after the action result executes. . (action的 方法执行完毕,并且结果执行完毕(数据绑定结束) 触发 ) |
OnResultExecuting |
Called by the ASP.NET MVC framework before the action result executes. . (action的 方法执行完毕,但是结果执行之前(数据绑定结束) 触发 ) |
详细MVC ActionFilter的资料请参照:http://msdn.microsoft.com/zh-cn/library/system.web.mvc.actionfilterattribute(v=vs.108).aspx.
利用ActionFilter其中的四个方法,我们可以完整的记录下整个网站进入Action之前传入的参数,以及Action执行之后返回的 ViewModel。
以下是具体的实现方式:
1.在MVC项目中添加一个ActionFilter特性。
/// <summary> /// the action filter to trace frontent request and response. /// </summary> public class LoggingAttribute : ActionFilterAttribute { /// <summary> /// Called when [action executing]. /// </summary> /// <param name="filterContext">The filter context.</param> public override void OnActionExecuting(ActionExecutingContext filterContext) { if (filterContext.ActionParameters != null) { // LoggingAttribute 只会拥有一个实例,并且运用于所有的Cotrollers,所以我们必须保证每一次Request只会记录自己的数据 filterContext.HttpContext.Items[HttpContextConstants.RequestData] = filterContext.ActionParameters; filterContext.HttpContext.Items[HttpContextConstants.Stopwatch] = Stopwatch.StartNew(); } base.OnActionExecuting(filterContext); } /// <summary> /// Called when [action executed]. /// </summary> /// <param name="filterContext">The filter context.</param> public override void OnActionExecuted(ActionExecutedContext filterContext) { string methodName = filterContext.ActionDescriptor.ActionName; string conrtrollerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName; object response = null; if (filterContext != null && filterContext.Result != null) { var result = filterContext.Result; //.net framework 提供了 7种 ActionResult ,这里需要看项目的设计,我们只需要分析各自项目会运用到哪些ActionResult,并且拿到相应的Model或者Data(如果没有返回值就不需要,Response就是null) if (result is ViewResultBase) { if ((result as ViewResultBase).Model != null) { response = (result as ViewResultBase).Model; } } else if (result is JsonResult) { if ((result as JsonResult).Data != null) { response = (result as JsonResult).Data; } } } TraceFrontendRequest(conrtrollerName, methodName, response); base.OnActionExecuted(filterContext); } /// <summary> /// Traces the frontend request. /// </summary> /// <param name="controllerName">Name of the controller.</param> /// <param name="methodName">Name of the method.</param> /// <param name="response">The response.</param> private void TraceFrontendRequest(string controllerName, string methodName, object response) { try { var request = HttpContext.Current.Items[HttpContextConstants.RequestData]; var stopWatch = HttpContext.Current.Items[HttpContextConstants.Stopwatch] as Stopwatch; long elapse = null == stopWatch ? 0 : stopWatch.ElapsedMilliseconds; string category = string.Format("{0}/{1}", controllerName, methodName); LogManager.TraceFrontendRequest( category, request, response, controllerName, methodName, elapse); } catch (Exception ex) { //log the error message } } } |
2. 序列化Response和Request
.net framework 提供了很多的序列化方法,比如XmlSerializer, JavaScriptSerializer, DataContractSerializer, DataContractJsonSerializer.
|
2.1序列化方法的选定:
在ActionFilterAttribute OnActionExecuting方法中,我们可以ActionExecutingContext.ActionParameters,以下是ActionExecutingContext的结构:
namespace System.Web.Mvc { public class ActionExecutingContext : ControllerContext { public ActionExecutingContext(); public ActionExecutingContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> actionParameters); public virtual ActionDescriptor ActionDescriptor { get; set; } public virtual IDictionary<string, object> ActionParameters { get; set; } public ActionResult Result { get; set; } } } |
Xml序列化不支持IDictionary类型,JavaScriptSerializer没有可读性,DataContractSerializer序列缺少必要的Contract,所以我们只能采用DataContractJsonSerializer。
2.2DataContractJsonSerializer使用的条件。
1) DataContractJsonSerialier在序列化的过程,必须知道对象的具体类型, 当序列化对象派生于某基类时,我们需要使用KnownTypes特性。
2) 在Controller中,如果返回的是Json对象,我们不能返回一个匿名类的Json对象(任何序列化方法都无法有效识别匿名类的类型,因此无法确定序列化的结构)。比如:
public JsonResult GetSubscriptions() { int total = 0; return new JsonResult() { Data = new { Rows = …, TotalSize = total, PageNum = …. PageSize = …. } }; } |
3. DataContractJsonSerializer 实现代码
由于ViewModel可能作为被返回的ViewModel,也可能是页面 Post回来的RequestParameters. 所以我们可以设计一个BaseModel类,用以实现KnownType特性。
1) BaseModel的实现
[KnownType("GetKnownTypes")] // for serialization public class BaseModel { /// <summary> /// Gets or sets the known types. /// </summary> /// <value> /// The known types. /// </value> private static List<Type> KnownTypes { get; set; } /// <summary> /// Gets the known types. /// </summary> /// <returns></returns> public static List<Type> GetKnownTypes() { return KnownTypes; } /// <summary> /// Initializes the <see cref="BaseModel"/> class. /// </summary> static BaseModel() { //只需要执行一次,运用反射,获取到所有继承与BaseModel的类的类型。 KnownTypes = new List<Type>(); try { foreach (Type type in Assembly.GetExecutingAssembly().GetTypes()) { if (!type.IsAbstract && type.IsSubclassOf(typeof(BaseModel))) { KnownTypes.Add(type); } } } catch (Exception ex) { //log error message } } } /// <summary> /// Subscription Details View Model /// </summary> public class SubscriptionDetailsViewModel : BaseModel { } |
2) DataContractJsonSerializer方法
/// <summary> /// Datas the contract serialize. /// </summary> /// <param name="obj">The obj.</param> /// <returns></returns> public static string DataContractSerialize(object obj) { if (null == obj) { return string.Empty; } Type objectType = obj.GetType(); //In case of primitive type or string type, just return the ToString value if (objectType.IsPrimitive || objectType == typeof(string) || obj is Exception) { return obj.ToString(); } //otherwise, return the xml serialization of the object string output = string.Empty; try { DataContractSerializer serializer = new DataContractSerializer(objectType); using (StringWriter sw = new StringWriter()) { using (XmlTextWriter writer = new XmlTextWriter(sw) { Formatting = Formatting.Indented }) { serializer.WriteObject(writer, obj); } output = sw.GetStringBuilder().ToString(); } } catch (Exception e) { //log error message } return output; } |
转载于:https://www.cnblogs.com/murder/archive/2012/11/28/Muder.html
.NET利用ActionFilter特性记录日志或者运行性能计数器。(log trace or perform perfcounter by actionFilter attribute)...相关推荐
- mvc4 利用filters特性来 实现自己的权限验证 之二
刚开始摸索C# MVC,也只是按图索骥,对C#的特性不是很懂,耐心看完相关文章,对特性的使用有了进一步理解. 1.特性类的命名规范:特性也是一个类,必须继承于System.Attribute类,命名规 ...
- 寻宝游戏 - 利用iBeacon特性设计的iOS线下寻宝游戏 - 物联网小游戏
寻宝游戏 - 利用iBeacon特性设计的iOS线下寻宝游戏 作者简介 科科香,程序员 方向:IoT,方案集成,喜好各种新鲜东东 转载请注明出处 iBeacon简介 iBeacon(下面简称Beaco ...
- 利用多态特性,创建一个手机类Phones,定义打电话的方式call,创建三个子类,并在各自的方法中重写方法,编写程序入口main()方法,实现多种手机打电话...
|--需求说明 利用多态特性,创建一个手机类Phones,定义打电话的方式call,创建三个子类,并在各自的方法中重写方法,编写程序入口main()方法,实现两种手机打电话 |--解题思路 采用简单工 ...
- 利用多态特性,编程创建一个手机类Phones,定义打电话方法call()。创建两个子类:苹果手机类IPhone和安卓手机类APhone,并在各自类中重写方法call(),编写程序入口main()方法
利用多态特性,编程创建一个手机类Phones,定义打电话方法call().创建两个子类:苹果手机类IPhone和安卓手机类APhone,并在各自类中重写方法call(),编写程序入口main()方法, ...
- 利用jdk自带的运行监控工具JConsole观察分析Java程序的运行 Jtop
利用jdk自带的运行监控工具JConsole观察分析Java程序的运行 原文链接 一.JConsole是什么 从Java 5开始 引入了 JConsole.JConsole 是一个内置 Java 性能 ...
- 利用PHP安装windows自动运行的服务,PHP程序可以实现长时间、自动运行、定时更新功能,直接可以用在项目中的类源代码...
为什么80%的码农都做不了架构师?>>> 什么 windows服务 ? Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运 ...
- 利用css特性布局页面制作京东特价框
布局技巧:利用css特性去制作京东价格图框: 类似步骤: 1.首先制作一个四边形的样式,对高度和宽度进行设置,两者设置为0px 2.原来制作一个四边形里面的一个三角形部分采取的是对颜色设置transp ...
- css3三角形兼容_利用css3特性写出三角形(兼容IE浏览器)
利用CSS写出三角形的效果 效果如图: 代码如下: .triangle-up { width:0px; height:0px; border-left:10px solid transparent; ...
- javascript 算法相关,如何利用指针特性求数组并集与交集
如何利用指针特性求数组并集与交集 javascript计算数组交集,并集,网上有很多,有些书也有介绍, 很多都是写一个set类,再添加一些方法,本质上都是利用了多次循环 我在写这个的时候,也是被别人问 ...
- Kali运行smod框架报错‘Conf‘ object has no attribute ‘use_dnet‘
Kali运行smod框架报错'Conf' object has no attribute 'use_dnet' 报错信息如下 解决方法 报错信息如下 // smod运行报错详细内容 Traceback ...
最新文章
- JS DATE对象详解
- 生产者消费者模式 php 【转】
- Java中常见的十八种异常!
- 遨游3.0 RC 版公布
- DB2 SQL性能调优秘笈pdf
- zemax验证高斯公式_ZEMAX 实验讲义
- c语言学习-求一元二次方程的根
- 在Java中==的一个坑
- 企业收集客户信息有哪些方式?
- c# 超时时间已到.在操作完成之前超时时间已过或服务器未响应,超时过期了。在操作完成或服务器没有响应之前经过的超时时间。声明已被终止...
- 前端工程化:vue代码检查工具vetur
- python matting后如何设置透明背景
- linux xen 管理,ARM平台上运行Xen 可同时管理linux和VxWorks
- 用word字体转换来代替手写作业--最详细
- ZYNQ学习之旅--PS_AXI_VDMA(利用VDMA实现将PS端的数据显示在PL端的HDMI上)
- DS18B20温度采集报警系统,原理及汇编、C语言实现
- C#输出Word文档
- 高仿网易云音乐一(可扫描本地音乐播放)
- CTF-RSA1(已知p、q、dp、dq、c)
- 剑网3指尖江湖开局门派选TA最好 叉叉助手伴你快意江湖
热门文章
- MyBatis实现一对一,一对多关联查询
- excel筛选,排序
- 威联通 ※ 群晖 虚拟机性能对比 我可能要碰瓷 eSir
- 安装光盘并重新启动计算机戴尔,戴尔电脑怎么设置光盘启动
- 华为路由器基本使用命令
- ERR Slot 741 is already busy (Redis::CommandError)
- 天线发射功率计算公式_天线增益的定义/计算公式/发射功率
- 推荐25个值得收藏的前端开源Awesome项目
- C# datagridview / datatable 导出带表头的excel的数据
- 2022数字化工地智慧防疫系统助力工地疫情防控实现人员、施工安全闭环管理