我们在构建WEBAPI项目时,通常需要构建一个全局的记录API 请求和返回 的功能,在WEBAPI框架下 我们通过自定义一个DelegateHandler来实现这个功能,

在.NET CORE框架下已经不存在DelegateHandler管道了,我们需要通过Middleware管道来实现。具体实现如下:

定义LoggingMiddleware

    public class GlobalApiLoggingMiddleware : IMiddleware
{
private readonly ILogger _logger; public GlobalApiLoggingMiddleware(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger("ApiLog");
}
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
        //在这里我们来拦截请求,收集日志
 await next.Invoke(context);
}
}

HttpContext的定义

可以看到里面的Request和Response对象 分别时 HttpRequest 和 HttpResponse,不再像在webapi框架下直接通过HttpRequestMessage、HttpResponseMessage来获取请求报文和返回报文。

这里需要花费一些技巧。

获取请求报文,

            //reuqest支持buff,否则body只能读取一次
context.Request.EnableBuffering();
//这里不要释放stream,否则后续读取request.body会报错
var reader = new StreamReader(context.Request.Body, Encoding.UTF8);
var requestStr = await reader.ReadToEndAsync();
            //var requestStr = reader.ReadToEnd(); 升级.net core 3.1后 会报 Synchronous operations are disallowed. 错误

首先类似于webapi框架下获取请求报文一样,需要先设置request buffer,这样request报文可以读取多次

其次获取报文的方式 是通过 stream获取,这里stream不要释放 不要释放 不要释放。重要的事情说三次。

获取返回报文 更加复杂一点

           Stream originalBody = context.Response.Body;

            try
{
using (var memStream = new MemoryStream())
{
context.Response.Body = memStream;
await next.Invoke(context); var request = context.Request;
var log = new ApiLogEntity()
{
Appkey = request.GetAppkey(),
ClientIp = request.GetClientRealIp(),
HttpMethod = request.Method,
Request = requestStr,
RequestId = request.GetRequestId(),
RequestUrl = request.Path.Value,
QueryString = request.QueryString.Value,
ServerIp = request.Host.Value,
StatusCode = context.Response.StatusCode
}; memStream.Position = ;
log.Response = await new StreamReader(memStream).ReadToEndAsync(); memStream.Position = ;
await memStream.CopyToAsync(originalBody); _logger.LogInformation(JsonConvert.SerializeObject(log));
}
}
finally
{
//重新给response.body赋值,用于返回
context.Response.Body = originalBody;
}

这里HttpResponse的body是不允许读取的!!所以这里的策略是 先给body赋值一个新的stream,

执行完action得到返回值后,可以读取我们自己定义的stream拿到返回报文

最后把返回值stream copy给原来的body对象,并重新赋给context.Response.Body,这里客户端可以正确返回了。

OK,结束!

.NET CORE之API日志收集的更多相关文章

  1. C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志

    C#实现多级子目录Zip压缩解压实例 参考 https://blog.csdn.net/lki_suidongdong/article/details/20942977 重点: 实现多级子目录的压缩, ...

  2. 在.NET Core中使用Exceptionless分布式日志收集框架

    一.Exceptionless简介 Exceptionless 是一个开源的实时的日志收集框架,它可以应用在基于 ASP.NET,ASP.NET Core,Web Api,Web Forms,WPF, ...

  3. asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程

    最近在学习张善友老师的NanoFabric 框架的时了解到Exceptionless : https://exceptionless.com/ !因此学习了一下这个开源框架!下面对Exceptionl ...

  4. Net Core免费开源分布式异常日志收集框架Exceptionless

    asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 https://www.cnblogs.com/yilezhu/p/9193723.htm ...

  5. 【转】asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程

    最近在学习张善友老师的NanoFabric 框架的时了解到Exceptionless : https://exceptionless.com/ !因此学习了一下这个开源框架!下面对Exceptionl ...

  6. 一套标准的ASP.NET Core容器化应用日志收集分析方案

    讲故事 关注我公众号的朋友,应该知道我写了一些云原生应用收集和分析相关的文章,其中内容大多聚焦某个具体的组件: 超级有用的TraceId,快点用起来吧! 如何利用NLog输出结构化日志,并在Kiban ...

  7. 微服务日志之.NET Core使用NLog通过Kafka实现日志收集

    一.前言 NET Core越来越受欢迎,因为它具有在多个平台上运行的原始.NET Framework的强大功能.Kafka正迅速成为软件行业的标准消息传递技术.这篇文章简单介绍了如何使用.NET(Co ...

  8. 循序渐进学.Net Core Web Api开发系列【10】:使用日志

    系列目录 循序渐进学.Net Core Web Api开发系列目录 本系列涉及到的源码下载地址:https://github.com/seabluescn/Blog_WebApi 一.本篇概述 本篇介 ...

  9. .NET Core使用NLog通过Kafka实现日志收集

    微服务日志之.NET Core使用NLog通过Kafka实现日志收集 https://www.cnblogs.com/maxzhang1985/p/9522017.html 一.前言 NET Core ...

随机推荐

  1. HDU 1398 Square Coins(母函数或dp)

    Square Coins Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  2. TCP连接建立与终止,及状态转换

    TCP连接建立 三路握手 三路握手发生在客户端发起connect请求到服务端accept返回中,在三路握手发生前,服务端必须准备好接受外来连接,这通常通过服务端调用 (socket.bind.list ...

  3. openwrt gstreamer实例学习笔记(五. gstreamer BUS)

    1)概述 BUS(总线) 是一个简单的系统,它采用自己的线程机制将一个管道线程的消息分发到一个应用程序当中.总线的优势是:当使用GStreamer的时候,应用程序不需要线程识别,即便GStreamer ...

  4. 键盘HOOK显示按键信息

    GetKeyNameText(MapVirtualKey(iKeyValue,0)<<16));//iKeyValue 的值为 VK_ESCAPE 等 LRESULT CALLBACK L ...

  5. 我遇到的错误curl: (7) Failed to connect to 127.0.0.1 port 1086: Connection refused

    今天我用curl命令,无论如何都是出现: curl: (7) Failed to connect to 127.0.0.1 port 1086: Connection refused 找了很久,不知道 ...

  6. java面试题(摘录)

    1.抽象,继承,封装,多态 2.基本数据类型的字节数 byte:1.int:4.char:2.long:8.float:4.double:8.boolean:1 和short:2 3.String , ...

  7. all rows from client_id can grow infinitely compared to a single node when hashing by client_id

    all rows from client_id can grow infinitely compared to a single node when hashing by client_id Re: ...

  8. hdfs namenode出错

    http://hadoop.apache.org/docs/r1.0.4/cn/hdfs_design.html 健壮性 HDFS的主要目标就是即使在出错的情况下也要保证数据存储的可靠性.常见的三种出 ...

  9. 求a + aa + aaa + aaaa + aaaaa ...的值,例如:1 + 11 + 111,2 + 22 + 222 + 2222 + 22222

    #include <stdio.h> unsigned superposition(unsigned m, unsigned n); int main() { printf("1 ...

  10. Codeforces Beta Round #25 (Div. 2 Only)D. Roads not only in Berland

    D. Roads not only in Berland time limit per test 2 seconds memory limit per test 256 megabytes input ...