思路:

通过重写 ActionFilterAttribute 拦截Action的请求及返回信息,实现对接口请求的监听。

最终效果如下:

全局启用需配置如下:

局部启用需配置如下:

源码如下:

  1     /// <summary>
2 /// 统一的接口访问监控日志,
3 /// 全局启用-请添加 GlobalConfiguration.Configuration.Filters.Add(new TimingFilterAttribute());
4 /// 局部启用(目前模式)-在Controller或者Action上添加Attribute注入即可
5 /// </summary>
6 public class TimingFilterAttribute : ActionFilterAttribute
7 {
8 private const string Key = "__action_recordtime__";
9 private const string TimeKey = "__action_receivetime__";
10 /// <summary>
11 /// 自定义参数
12 /// </summary>
13 public string Message { get; set; }
14
15 public override Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
16 {
17 if (IsRecordTime(actionContext))
18 {
19 return base.OnActionExecutingAsync(actionContext, cancellationToken);
20 }
21 // ReqParms= GetRequestValues(actionContext);
22 var stopWatch = new Stopwatch();
23 actionContext.Request.Properties[Key] = stopWatch;
24 actionContext.Request.Properties[TimeKey] = DateTime.Now.ToBinary();
25 stopWatch.Start();
26 return base.OnActionExecutingAsync(actionContext, cancellationToken);
27 }
28
29 public override Task OnActionExecutedAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
30 {
31 if (!actionExecutedContext.Request.Properties.ContainsKey(Key) || !actionExecutedContext.Request.Properties.ContainsKey(TimeKey))
32 {
33 return base.OnActionExecutedAsync(actionExecutedContext, cancellationToken);
34 }
35 object beginTime = null;
36 if (!actionExecutedContext.Request.Properties.TryGetValue(TimeKey, out beginTime))
37 {
38 return base.OnActionExecutedAsync(actionExecutedContext, cancellationToken);
39 }
40 var stopWatch = actionExecutedContext.Request.Properties[Key] as Stopwatch;
41 if (stopWatch == null)
42 {
43 return base.OnActionExecutedAsync(actionExecutedContext, cancellationToken);
44 }
45 stopWatch.Stop();
46
47 DateTime starttime = DateTime.FromBinary(Convert.ToInt64(beginTime));
48 HttpRequest request = HttpContext.Current.Request;
49 string token = string.Empty;
50 var appkey = string.Empty;
51 if (request.Headers.AllKeys.Contains("Token")) { token = request.Headers["Token"]; }
52
53 if (request.Headers.AllKeys.Contains("AppKey")) { appkey = request.Headers["AppKey"]; }
54
55 var actionName = actionExecutedContext.ActionContext.ActionDescriptor.ActionName;
56 var controllerName = actionExecutedContext.ActionContext.ActionDescriptor.ControllerDescriptor.ControllerName;
57
58 var ip = request.UserHostAddress;
59 var UserHostName = request.UserHostName;
60 var paramaters = GetRequestValues(actionExecutedContext);
61 // var paramaters = ReqParms;//获取入参
62 var executeResult = GetResponseValues(actionExecutedContext);//获取response响应的结果
63
64 var RequestUri = request.Url.AbsoluteUri;
65 var MethodType= request.HttpMethod.ToString();
66 Bondex.Core.BizTool.LogPlat.LogHelper.Info($"{controllerName}/{actionName}", "E帐通接口监控服务", "TimingFilterAttribute", $"",
67 $"当前接口路径:{RequestUri},请求方式:{MethodType},请求时间:{starttime.ToString("yyyy-MM-dd HH:mm:ss:fff")},返回时间{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")},接口执行时间:{stopWatch.Elapsed};请求IP:{ip},请求DNS:{UserHostName},请求入参:{paramaters},返回值:{executeResult},备注:{Message}");
68 return base.OnActionExecutedAsync(actionExecutedContext, cancellationToken);
69
70 }
71 /// <summary>
72 /// 读取request 的提交内容
73 /// </summary>
74 /// <param name="actionExecutedContext"></param>
75 /// <returns></returns>
76 public string GetRequestValues(HttpActionExecutedContext actionExecutedContext)
77 {
78 string result = String.Empty;
79 using (var stream = actionExecutedContext.Request.Content.ReadAsStreamAsync().Result)
80 {
81 if (stream.CanSeek)
82 {
83 stream.Position = 0;
84 }
85 result = actionExecutedContext.Request.Content.ReadAsStringAsync().Result;
86 }
87
88 return result;
89 }
90
91 /// <summary>
92 /// 读取action返回的result
93 /// </summary>
94 /// <param name="actionExecutedContext"></param>
95 /// <returns></returns>
96 public string GetResponseValues(HttpActionExecutedContext actionExecutedContext)
97 {
98 Stream stream = actionExecutedContext.Response.Content.ReadAsStreamAsync().Result;
99 Encoding encoding = Encoding.UTF8;
100 /*
101 这个StreamReader不能关闭,也不能dispose, 关了就傻逼了
102 因为你关掉后,后面的管道 或拦截器就没办法读取了
103 */
104 var reader = new StreamReader(stream, encoding);
105 string result = reader.ReadToEnd();
106 /*
107 这里也要注意: stream.Position = 0;
108 当你读取完之后必须把stream的位置设为开始
109 因为request和response读取完以后Position到最后一个位置,交给下一个方法处理的时候就会读不到内容了。
110 */
111 stream.Position = 0;
112 return result;
113 }
114 /// <summary>
115 /// 判断是否拦截请求,记录接口信息
116 /// </summary>
117 /// <param name="actionContext"></param>
118 /// <returns></returns>
119 private static bool IsRecordTime(HttpActionContext actionContext)
120 {
121 return actionContext.ActionDescriptor.GetCustomAttributes<NoRecordTimeAttribute>().Any() ||
122 actionContext.ControllerContext.ControllerDescriptor.GetCustomAttributes<NoRecordTimeAttribute>().Any();
123 }
124 }
125
126 [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
127 public class NoRecordTimeAttribute : Attribute
128 {
129
130 }

[.Net]Framwork WebAPI添加接口请求监控的更多相关文章

  1. SpringBoot整合knife4j框架(可生成离线接口文档),并设置接口请求头token默认值

    功能和swagger类似 官网地址:https://doc.xiaominfo.com/knife4j/ 这个框架可以设置返回字段的描述 引入依赖 <dependency> <gro ...

  2. SpringBoot整合Swagger框架 ,并设置接口请求头token默认值

      引入maven依赖 <!-- swagger2--> <dependency> <groupId>io.springfox</groupId> &l ...

  3. WebApi接口请求失败,找不到资源。

    WebApi开发接口,实现同步数据库的数据给安卓. public class UserInfoController : ApiControllerBase { private UserBLL user ...

  4. ASP.NET WebApi服务接口如何防止重复请求实现HTTP幂等性

    一.背景描述与课程介绍 明人不说暗话,跟着阿笨一起玩WebApi.在我们平时开发项目中可能会出现下面这些情况; 1).由于用户误操作,多次点击网页表单提交按钮.由于网速等原因造成页面卡顿,用户重复刷新 ...

  5. restful接口就是url嘛,通过http请求发起访问。那接口进行监控,就可以监控这个restful url嘛

    EasyAPI接口管理系统 专注API接口监控,让您的API接口更稳定,与APP更紧密 + 购买监控服务 接口性能分析 分析App对应的API接口请求性能,包含HTTP响应时间.吞吐率.HTTP错误率 ...

  6. ASP.NET Core 入门(2)(WebApi接口请求日志 Request和Response)

    以前 .NET Framework WebApi 记录接口访问日志,一般是通过Filter的方式进行拦截,通过重写ActionFilterAttribute的OnActionExecuting实现拦截 ...

  7. ASP.NET Web API 接口执行时间监控

    软件产品常常会出现这样的情况:产品性能因某些无法预料的瓶颈而受到干扰,导致程序的处理效率降低,性能得不到充分的发挥.如何快速有效地找到软件产品的性能瓶颈,则是我们感兴趣的内容之一. 在本文中,我将解释 ...

  8. 使用 NLog 给 Asp.Net Core 做请求监控

    为了减少由于单个请求挂掉而拖垮整站的情况发生,给所有请求做统计是一个不错的解决方法,通过观察哪些请求的耗时比较长,我们就可以找到对应的接口.代码.数据表,做有针对性的优化可以提高效率.在 asp.ne ...

  9. Asp.Net WebAPI配置接口返回数据类型为Json格式

    Asp.Net WebAPI配置接口返回数据类型为Json格式   一.默认情况下WebApi 对于没有指定请求数据类型类型的请求,返回数据类型为Xml格式 例如:从浏览器直接输入地址,或者默认的XM ...

  10. C# 动态创建SQL数据库(二) 在.net core web项目中生成二维码 后台Post/Get 请求接口 方式 WebForm 页面ajax 请求后台页面 方法 实现输入框小数多 自动进位展示,编辑时实际值不变 快速掌握Gif动态图实现代码 C#处理和对接HTTP接口请求

    C# 动态创建SQL数据库(二) 使用Entity Framework  创建数据库与表 前面文章有说到使用SQL语句动态创建数据库与数据表,这次直接使用Entriy Framwork 的ORM对象关 ...

随机推荐

  1. hutools密码算法库

    hutool密码算法库 一.开发背景 Hutool针对Bouncy Castle做了简化包装,用于实现国密算法中的SM2.SM3.SM4. 国密算法工具封装包括: 非对称加密和签名:SM2 摘要签名算 ...

  2. Java方法之递归详解【重点】

    递归详解 A方法调用B方法,我们很容易理解! 递归就是:A方法调用A方法!就是自己调用自己. 利用递归可以用简单的程序来解决一些复杂的问题.它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较 ...

  3. js任务执行顺序

    JS 线程简述 js是单线程的,一次只能执行一个任务,执行完毕后才能继续下一个. js执行任务的方式也叫作同步执行,同步和异步与我们平时理解的不太一样,平时的同步我们会认为是多个事情一起做,但是在js ...

  4. HDFS学习记录

    HDFS 1.hdfs整体工作机制: 1>hdfs:分布式文件系统. hdfs:分布式文件系统 hdfs有着文件系统共同的特征: 2>有目录结构,顶层目录是:  / 3>系统中存放的 ...

  5. CSS3-animation实现走马灯效果

    动画animation 1.先定义动画: @keyframes 动画名称( from{} to{} ) 或者 @keyframes 动画名称( 0%{} 50%{} 100%{} ) 百分号指的是动画 ...

  6. L2 Gracia Final OpCodz

    [83] Gracia Final Client 00 SendLogOut 01 RequestAttack 03 RequestStartPledgeWar 04 RequestReplyStar ...

  7. 快速搭建一个spring cloud 子模板--好记性不如烂笔头

    建 application.yml 文件 server: # 服务端口号 port: 7609spring: application: # 服务名称 - 服务之间使用名称进行通讯 name: serv ...

  8. Excel Vlookup用法和常见报错#REF! #Value!

    VLOOKUP(E2,$A$2:$C$5,2,FALSE) E2 为选中查找的条件 $A$2:$C$5 1为需要查找的区域,这个区域一般是固定的,所以要加上$符号 2这个区域可以在前面加上SHEET2 ...

  9. c语言实现单链表的倒叙

    bool upsidedown_list(LinkList L) { Lnode *head, *tmp, *oldhead; head = L; tmp = L->next; oldhead ...

  10. python pip 下载库速度慢,2命令永久解决

    背景:pip 下载速度慢,超时 加速:永久性2条命令,拿去不谢 pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/si ...