[.Net]Framwork WebAPI添加接口请求监控
思路:
通过重写 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添加接口请求监控的更多相关文章
- SpringBoot整合knife4j框架(可生成离线接口文档),并设置接口请求头token默认值
功能和swagger类似 官网地址:https://doc.xiaominfo.com/knife4j/ 这个框架可以设置返回字段的描述 引入依赖 <dependency> <gro ...
- SpringBoot整合Swagger框架 ,并设置接口请求头token默认值
引入maven依赖 <!-- swagger2--> <dependency> <groupId>io.springfox</groupId> &l ...
- WebApi接口请求失败,找不到资源。
WebApi开发接口,实现同步数据库的数据给安卓. public class UserInfoController : ApiControllerBase { private UserBLL user ...
- ASP.NET WebApi服务接口如何防止重复请求实现HTTP幂等性
一.背景描述与课程介绍 明人不说暗话,跟着阿笨一起玩WebApi.在我们平时开发项目中可能会出现下面这些情况; 1).由于用户误操作,多次点击网页表单提交按钮.由于网速等原因造成页面卡顿,用户重复刷新 ...
- restful接口就是url嘛,通过http请求发起访问。那接口进行监控,就可以监控这个restful url嘛
EasyAPI接口管理系统 专注API接口监控,让您的API接口更稳定,与APP更紧密 + 购买监控服务 接口性能分析 分析App对应的API接口请求性能,包含HTTP响应时间.吞吐率.HTTP错误率 ...
- ASP.NET Core 入门(2)(WebApi接口请求日志 Request和Response)
以前 .NET Framework WebApi 记录接口访问日志,一般是通过Filter的方式进行拦截,通过重写ActionFilterAttribute的OnActionExecuting实现拦截 ...
- ASP.NET Web API 接口执行时间监控
软件产品常常会出现这样的情况:产品性能因某些无法预料的瓶颈而受到干扰,导致程序的处理效率降低,性能得不到充分的发挥.如何快速有效地找到软件产品的性能瓶颈,则是我们感兴趣的内容之一. 在本文中,我将解释 ...
- 使用 NLog 给 Asp.Net Core 做请求监控
为了减少由于单个请求挂掉而拖垮整站的情况发生,给所有请求做统计是一个不错的解决方法,通过观察哪些请求的耗时比较长,我们就可以找到对应的接口.代码.数据表,做有针对性的优化可以提高效率.在 asp.ne ...
- Asp.Net WebAPI配置接口返回数据类型为Json格式
Asp.Net WebAPI配置接口返回数据类型为Json格式 一.默认情况下WebApi 对于没有指定请求数据类型类型的请求,返回数据类型为Xml格式 例如:从浏览器直接输入地址,或者默认的XM ...
- C# 动态创建SQL数据库(二) 在.net core web项目中生成二维码 后台Post/Get 请求接口 方式 WebForm 页面ajax 请求后台页面 方法 实现输入框小数多 自动进位展示,编辑时实际值不变 快速掌握Gif动态图实现代码 C#处理和对接HTTP接口请求
C# 动态创建SQL数据库(二) 使用Entity Framework 创建数据库与表 前面文章有说到使用SQL语句动态创建数据库与数据表,这次直接使用Entriy Framwork 的ORM对象关 ...
随机推荐
- phaclon 初学者遇到的问题!
1,框架安装 需要安装PHALCON扩展. 2,Nginx伪静态 配置 3,app.ini 常量配置等配置 4,主体目录结构 互相调用及 类的注册服务 依赖注入 自动加载项问题. 5,数据库相关操 ...
- httpcanary高级版--不闪退!!!!
地址 https://wwm.lanzouw.com/iOf7Hz11s4j 密码:45of
- 小程序中使用less
小程序中使用Less 原生小程序不支持less,其他基于小程序的框架大体都支持,如wepy,mpvue,taro等.但是仅仅因为一个less功能,而且引入一个框架,肯定是不可取的.因此可以用以下方式来 ...
- Python批量修改文件名中所包含指定关键字的文件
1.去掉下图中各文件名中的'xx' 2.Python代码如下(仅供参考) import os, os.path, time def rename(file, keyword): #file: 需要修改 ...
- Java集合-LinkedHashSet
LinkedHashSet 重点: LinkedHashSet 不允许重复元素,与 HashSet的区别是:它是有序的 LinkedHashSet 底层结构是 数组table + 双向链表 [介绍] ...
- 织梦清除文章后后台页码异常怎么办?dedecms页码缓存更新设置
织梦dedecms当我们清除大量文章后,发现织梦后台文章列表的页码还是原来的数量或者页码显示异常,该怎么办呢?其实是因为dedecms页码有缓存更新设置,DeDeCMS有缓存机制,有些比较费时的SQl ...
- <四>JMeter数据库连接/后置处理器/断言简介
一.数据库连接 1.右键线程组添加--配置元件--JDB Cconnection Configuration 2.配置如下: URL为数据路连接地址,用户名密码为数据库用户名和密码 3.添加一个JDB ...
- npm start ERROR
npm start 遇到问题 Attempting to bind to HOST environment variable: x86_64-apple-darwin13.4.0 If this wa ...
- Navicate 链接 MySQL8.0版本 连接报错问题 1251错误,Clinent does not support authentication protocol requested by server
网上查到的原因是: mysql8 之前的版本中加密规则是mysql_native_password: mysql8之后,加密规则是caching_sha2_password: 找到的解决方法是: 把m ...
- vue后台管理系统——商品管理模块
电商后台管理系统的功能--商品管理模块 商品管理概述 商品管理模块用于维护电商平台的商品信息,包括商品的类型.参数.图片.详情等信息. 通过商品管理模块可以实现商品的添加.修改.展示和删除等功能. 1 ...