思路:

通过重写 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. SPI接口

    串行外设接口(Serial Peripheral Interface)是一种同步外设接口,它可以使单片机与各种外围设备以串行方式进行通信以交换信息.SPI最早是Motorola公司提出的全双工三线同步 ...

  2. Mysql数据库基础第二章:(十)联合查询

    Mysql数据库基础系列 软件下载地址 提取码:7v7u 数据下载地址 提取码:e6p9 mysql数据库基础第一章:(一)数据库基本概念 mysql数据库基础第一章:(二)mysql环境搭建 mys ...

  3. continue练习

    using System; namespace continue_的练习 { class Program { static void Main(string[] args) { int sum = 0 ...

  4. React 事件绑定this指向

    1. 推荐:使用class的实例方法 class Hello extends React.Component { handleClick = () => { this.setState({ .. ...

  5. miscmisc --攻防世界

    题目: (1)解压后将图片放入16进制编辑器,搜索字符串flag发现 图片应该还包含其他文件 (2)使用foremost进行分离,得到压缩包,打开压缩包又有一张图片 (3) 图片同样使用编辑器查看,也 ...

  6. pg的json类型

    以下举例说明: postgres=# select '{"b":1,"a":2}'::json; json --------------- {"b&q ...

  7. 【python】读取nc文件

    读取nc文件前的准备,安装一些库 1.先把几个用到的库下载 Cartopy 简介与安装(转载) - 简书 (jianshu.com) Python Extension Packages for Win ...

  8. web端测试的测试点和注意事项【转载】

    文章来源:作者:simplesally 出处:https://www.cnblogs.com/simple1025/   [转载] 工作中接触了不同类型的web端系统,内容不同,需求不同,测试关注点也 ...

  9. Mixly呼吸灯及可调灯(物联网)

    3挡可调灯 2秒呼吸灯

  10. Linux deploy 32位系统 怎么安装宝塔怎么安装linux系统安装宝塔后搭建网站

    getconf LONG_BIT 获取当前linux系统位数