实现的原理比较直接,定义一个MessageHandler记录WebAPI的请求记录,然后将这些请求日志推送到客户端,客户端就是一个查看日志的页面,实时将请求日志展示在页面中。

这个例子的目的是演示如何在PersistentConnection类外部给Clients推送消息

实现过程

一、服务端

服务端同时具备SignalR和WebAPI的功能,通过定义一个记录日志的MessageHandler实现对WebAPI请求的拦截,并生成请求记录,然后推送到客户端

step 1

创建一个具备WebAPI功能的站点,为了简化起见,设置Authentication为No Authentication

step 2

创建一个DelegatingHandler,用于记录WebAPI日志,代码如下

下面代码没有涉及到SignalR的功能,日志展示是通过ILoggingDisplay接口传入

public class LoggingHandler : DelegatingHandler
{
private static readonly string _loggingInfoKey = "loggingInfo"; private ILoggingDisplay _loggingDisplay; public LoggingHandler(ILoggingDisplay loggingDisplay)
{
_loggingDisplay = loggingDisplay;
} public LoggingHandler(HttpMessageHandler innerHandler, ILoggingDisplay loggingDisplay)
: base(innerHandler)
{
_loggingDisplay = loggingDisplay;
} protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
LogRequestLoggingInfo(request);
return base.SendAsync(request, cancellationToken).ContinueWith(task =>
{
var response = task.Result;
LogResponseLoggingInfo(response);
return response;
});
} private void LogRequestLoggingInfo(HttpRequestMessage request)
{
var info = new ApiLoggingInfo();
info.HttpMethod = request.Method.Method;
info.UriAccessed = request.RequestUri.AbsoluteUri;
info.IpAddress = HttpContext.Current != null ? HttpContext.Current.Request.UserHostAddress : "0.0.0.0";
info.StartTime = DateTime.Now;
ExtractMessageHeadersIntoLoggingInfo(info, request.Headers.ToList());
request.Properties.Add(_loggingInfoKey, info);
} private void LogResponseLoggingInfo(HttpResponseMessage response)
{
object loggingInfoObject = null;
if (!response.RequestMessage.Properties.TryGetValue(_loggingInfoKey, out loggingInfoObject))
{
return;
}
var info = loggingInfoObject as ApiLoggingInfo;
if (info == null)
{
return;
}
info.HttpMethod = response.RequestMessage.Method.ToString();
info.ResponseStatusCode = response.StatusCode;
info.ResponseStatusMessage = response.ReasonPhrase;
info.UriAccessed = response.RequestMessage.RequestUri.AbsoluteUri;
info.IpAddress = HttpContext.Current != null ? HttpContext.Current.Request.UserHostAddress : "0.0.0.0";
info.EndTime = DateTime.Now;
info.TotalTime = (info.EndTime - info.StartTime).TotalMilliseconds;
_loggingDisplay.Display(info);
} private void ExtractMessageHeadersIntoLoggingInfo(ApiLoggingInfo info, List<KeyValuePair<string, IEnumerable<string>>> headers)
{
headers.ForEach(h =>
{
var headerValues = new StringBuilder(); if (h.Value != null)
{
foreach (var hv in h.Value)
{
if (headerValues.Length > )
{
headerValues.Append(", ");
}
headerValues.Append(hv);
}
}
info.Headers.Add(string.Format("{0}: {1}", h.Key, headerValues.ToString()));
});
}
}

LoggingHandler

step 3

引入SignalR相关packages

Install-Package Microsoft.AspNet.SignalR

新建一个PersistentConnection,代码为空即可(因为不涉及到客户端调用,推送也是在类的外部执行)

public class RequestMonitor : PersistentConnection
{
}

添加一个Startup类

public void Configuration(IAppBuilder app)
{
       app.MapSignalR<RequestMonitor>("/monitor");
}

step 4

创建一个类实现ILoggingDisplay接口,用SignalR推送的方式实现这个接口

代码比较关键的部分就是通过GlobalHost.ConnectionManager获取当前应用程序的connectionContext,得到这个context就可以类似在PersistentConnection内部给clients推送消息

public class SignalRLoggingDisplay : ILoggingDisplay
{
/// <summary>
/// PersistentConnection上下文
/// </summary>
private static IPersistentConnectionContext connectionContext = GlobalHost.ConnectionManager.GetConnectionContext<RequestMonitor>(); public void Display(ApiLoggingInfo loggingInfo)
{
var message = new StringBuilder();
message.AppendFormat("StartTime:{0},Method:{1},Url:{2},ReponseStatus:{3},TotalTime:{4}"
, loggingInfo.StartTime, loggingInfo.HttpMethod, loggingInfo.UriAccessed, loggingInfo.ResponseStatusCode, loggingInfo.TotalTime);
message.AppendLine();
message.AppendFormat("Headers:{0},Body:{1}", string.Join(",", loggingInfo.Headers), loggingInfo.BodyContent);
connectionContext.Connection.Broadcast(message.ToString());
}

SignalRLoggingDisplay

step 5

在WebApiConfig的Register方法中添加自定义的handler

public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
); config.MessageHandlers.Add(new LoggingHandler(new SignalRLoggingDisplay()));
}

RegisterHandler

到此完成服务端的功能实现

二、客户端

客户端只需要一个监控页面,html页面足矣,其主要功能是提供开始监控、停止监控功能,其他都是接收服务端的推送并展示功能代码。

<!DOCTYPE html>
<html>
<head>
<title>Web API页面实时请求监控</title>
<meta charset="utf-8" />
</head>
<body>
<h1>Web API Request Logs</h1>
<div>
<input type="button" value="start" id="btnStart"/>
<input type="button" value="stop" id="btnStop"/>
<input type="button" value="clear" id="btnClear"/>
</div>
<ul id="requests"></ul>
<script src="/Scripts/jquery-1.10.2.min.js"></script>
<script src="/Scripts/jquery.signalR-2.2.0.min.js"></script>
<script>
$(function () {
var requests = $("#requests");
var startButton = $("#btnStart");
var stopButton = $("#btnStop");
var connection = null; enable(stopButton, false);
enable(startButton, true); startButton.click(function () {
startConnection();
enable(stopButton, true);
enable(startButton, false);
}); $("#btnClear").click(function () {
$("#requests").children().remove();
}); stopButton.click(function () {
stopConnection();
enable(stopButton, false);
enable(startButton, true);
}); function startConnection() {
stopConnection();
connection = $.connection("/monitor");
connection.start()
.fail(function () {
console.log("connect failed");
});
connection.received(function (data) {
data = data.replace(/\r\n/g, "<br/>")
data = data.replace(/\n/g, "<br/>");
requests.append("<li>" + data + "</li>");
});
} function stopConnection() {
if (connection != null){
connection.stop();
}
} function enable(button, enabled) {
if (enabled) {
button.removeAttr("disabled");
}
else {
button.attr("disabled", "disabled");
}
}
});
</script>
</body>
</html>

Monitor

示例代码下载

用SignalR实现实时查看WebAPI请求日志的更多相关文章

  1. 实时查看docker容器日志

    实时查看docker容器日志 $ sudo docker logs -f -t --tail 行数 容器名 例:实时查看docker容器名为s12的最后10行日志 $ sudo docker logs ...

  2. linux下打开、关闭tomcat,实时查看tomcat执行日志

     启动:通常是运行sh tomcat/bin/startup.sh   停止:通常是运行sh tomcat/bin/shutdown.sh脚本命令   查看:运行ps -ef |grep tomc ...

  3. 查看 redis 请求日志

    转: 查看 redis 请求日志 2019-05-29 15:34:41 打卤 阅读数 1980更多 分类专栏: other   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转 ...

  4. 如何实时查看Linux下日志

    以下以Tomcat为例子,其他WEB服务器目录自己灵活修改即可: 1.先切换到:cd usr/local/tomcat5/logs2.tail -f catalina.out3.这样运行时就可以实时查 ...

  5. 【linux】linux重启tomcat + 实时查看tomcat启动日志

    linux重启tomcat命令: http://www.cnblogs.com/plus301/p/6237468.html linux查看toncat实时的启动日志: https://www.cnb ...

  6. nginx查看post请求日志

    在http段加上 log_format access '$remote_addr - $remote_user [$time_local] "$request" $status $ ...

  7. ASP.NET Web API 2系列(三):查看WebAPI接口的详细说明及测试接口

    引言 前边两篇博客介绍了Web API的基本框架以及路由配置,这篇博客主要解决在前后端分离项目中,为前端人员提供详细接口说明的问题,主要是通过修改WebApi HelpPage相关代码和添加WebAp ...

  8. linux下查看tomcat的日志

    工作期间有碰到服务器日志相关的,需要看tomcat运行日志,简单搜了下,摘为随笔,以供参考 一种是利用docker查看 1.使用dockerdocker logs -f -t --since=&quo ...

  9. SignalR实现实时日志监控

    .net SignalR实现实时日志监控   摘要 昨天吃饭的时候,突然想起来一个好玩的事,如果能有个页面可以实时的监控网站或者其他类型的程序的日志,其实也不错.当然,网上也有很多成熟的类似的监控系统 ...

随机推荐

  1. 1393: Robert Hood 旋转卡壳 凸包

    http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1393 http://poj.org/problem?id=2187 Beauty Contest ...

  2. Jquery,jquery-cookie.js 做的点击记住用户名和密码!

    <!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8" ...

  3. jsp+servlet 中文乱码问题

    一. 由于doget和dopost的处理方式不同,在做servlet的时候遇到这样一个问题:用doPost获得的参数只要加上“request.setCharacterEncoding("ut ...

  4. OpenLayers工作原理

    1.数据组织 OpenLayers通过同层(Layer)进行组织渲染,然后通过数据源设置具体的地图数据来源.因此,Layer与Source是密切相关的对应关系,缺一不可.Layer可看做渲染地图的层容 ...

  5. 3.多线程NSOperation

    1.NSOperation的基本操作 使用NSOperation的两个子类,NSInvocationOperation 和 NSBlockOperation 创建操作,然后将操作添加到队列中去执行 / ...

  6. JavaScript中的apply和call函数详解(转)

    每个JavaScript函数都会有很多附属的(attached)方法,包括toString().call()以及apply().听起来,你是否会感到奇怪,一个函数可能会有属于它自己的方法,但是记住,J ...

  7. 货运APP雨后春笋 传统物流模式将被改变

    移动互联网正在改变我们的生活方式,各种手机APP充斥着人们的生活,物流行业也不例外.货运APP的出现,对于物流行业是一个提升的机会,也是迈向标准化和专业化的一个有效途径.有专家预测,这将为物流行业的发 ...

  8. Good Bye 2015 D. New Year and Ancient Prophecy

    D. New Year and Ancient Prophecy time limit per test 2.5 seconds memory limit per test 512 megabytes ...

  9. IBM WebSphere MQ的oracle的jdbc

    一.IBM WebSphere MQ7.0的jdbc支持数据库有: DB2 Informix Informix_With_Date_Format Microsoft_SQL_Server Oracle ...

  10. 【转载】免费台北.edu教育邮箱及Office 365 Education申请

    免费的邮箱非常多,但是免费的.edu教育邮箱却很少有.记得上次不少人寻找.edu教育邮箱还是因为国外一家VPS商家推出的专门针对学生的优惠包,使用.edu教育邮箱就可以获得50美元的优惠,真的很划算. ...