ASP.NET Core 如何记录每次响应的Response信息 - sky 胡萝卜星星 - CSDN博客

原文: ASP.NET Core 如何记录每次响应的Response信息 - sky 胡萝卜星星 - CSDN博客

上一篇文章中我们已经成功的记录了Request部分的信息,现在我们来看下如何记录Response的内容。

相比于Request,Response额外多了个StatusCode,然后内容都是通过Body读取,不过不同于Request.Body的只读,Response.Body是个只写的数据流。
Response.Body

可以看到默认Response.Body数据流数据类型为Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpResponseStream。通过查看其源代码,我们可以看到该数据流其实是个空壳,其仅仅是IHttpResponseControl的外部封装,因为前面已经有了替换Request.Body的经验,所以此处理所当然的,我们也应该将默认的Response.Body替换成一个可以读取的输出流。

为了保证通用,我们肯定不能按照HttpResponseStream的做法来重写一个可以读取并且可以重新设置位置的Stream,所以此处思路上直接简单的考虑对MemoryStream进行封装,其内部包含默认的HttpResponseStream,这样不管未来实际Response.Body究竟是什么,我们都可以做到从中读取并恢复数据流当前位置,保证程序的正确运行。

通过查看HttpResponseStream源代码,我们已经可以知道其核心是WriteFlush两个方法,既然是打算对MemoryStream进行封装,那么我们也需要了解下其源代码。通过源码,我们可以发现其BeginWriteWriteByteWriteAsync等方法底层其实都是在调用Write方法,再加上必需的DisposeFlush,所以最终我们得到如下代码

    public class MemoryWrappedHttpResponseStream : MemoryStream
    {
        private Stream _innerStream;
        public MemoryWrappedHttpResponseStream(Stream innerStream)
        {
            this._innerStream = innerStream ?? throw new ArgumentNullException(nameof(innerStream));
        }
        public override void Flush()
        {
            this._innerStream.Flush();
            base.Flush();
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            base.Write(buffer, offset, count);
            this._innerStream.Write(buffer, offset, count);
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            if (disposing)
            {
                this._innerStream.Dispose();
            }
        }

        public override void Close()
        {
            base.Close();
            this._innerStream.Close();
        }
    }
12345678910111213141516171819202122232425262728293031323334
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

然后我们将上篇内容中读取数据流的代码稍作调整

        private async Task<string> ReadBodyAsync(HttpResponse response)
        {
            if (response.Body.Length > 0)
            {
                //var position = response.Body.Position;
                response.Body.Seek(0, SeekOrigin.Begin);
                var encoding = this.GetEncoding(response.ContentType);
                var retStr = await ReadStreamAsync(response.Body, encoding, false).ConfigureAwait(false);
                //response.Body.Position = position;
                //读取完成后再重新赋值位置这个过程可能不需要,因为数据流是只写的
                return retStr;
            }
            return null;
        }

        private Encoding GetEncoding(string contentType)
        {
            var mediaType = contentType == null ? default(MediaType) : new MediaType(contentType);
            var encoding = mediaType.Encoding;
            if (encoding == null)
            {
                encoding = Encoding.UTF8;
            }
            return encoding;
        }

        private void EnableReadAsync(HttpResponse response)
        {
            if (!response.Body.CanRead || !response.Body.CanSeek)
            {
                response.Body = new MemoryWrappedHttpResponseStream(response.Body);
            }
        }

        private async Task<string> ReadStreamAsync(Stream stream, Encoding encoding,bool forceSeekBeginZero=true)
        {
            using (StreamReader sr = new StreamReader(stream, encoding, true, 1024, true))//这里注意Body部分不能随StreamReader一起释放
            {
                var str = await sr.ReadToEndAsync();
                if (forceSeekBeginZero)
                {
                    stream.Seek(0, SeekOrigin.Begin);//内容读取完成后需要将当前位置初始化,否则后面的InputFormatter会无法读取
                }
                return str;
            }
        }
12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

这样如何读取Body部分的准备工作就做完了,下面我们要做的就是在中间件的InvokeAsyncInvoke方法中声明相关的调用,其大致代码如下

        public async Task InvokeAsync(HttpContext context)
        {
            this.EnableReadAsync(context.Response);

            context.Response.OnCompleted(async o =>
            {
                var c = o as HttpContext;
                if (c != null)
                {
                    var retStr = await this.ReadBodyAsync(c.Response).ConfigureAwait(false);
                    //this._logger.LogDebug("Response at:{Time} Response:{Response}", DateTime.Now, retStr);
                }
            }, context);
            await _next(context);
        }
123456789101112131415
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

上面已经完成了如何在中间件中读取Response.Body,但实际不可能所有的响应都要做记录,另外上面的方法其实额外消耗了服务器内存(而且是大量),所以我们应该还要研究下如何筛选哪些请求需要记录,然后在此基础上再确认哪些响应内容应当被记录,这些将在下次研究完成后再述。

posted on 2019-05-28 14:12 NET未来之路 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/lonelyxmas/p/10937017.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将ASP.NET Core Angular项目部署到IIS上,并且遇到"non-js module files deprecated"的问题。 首先,我们需要确保我们正在使用的是最新版本的ASP.NET Core和Angular。新版本通常会修复旧版中的已知问题。 然后,我们需要检查我们的Angular项目中是否有使用到非JS模块文件(non-js module files)。这些文件可能是早期版本中的遗留文件,因此被标记为过时(deprecated)。 要解决这个问题,我们可以按照以下步骤进行操作: 1. 检查Angular项目中的Angular.json配置文件。在该文件中,我们需要确保所有的非JS模块文件都被正确地排除在构建过程之外。这可以通过在 "build" 部分中的 "assets" 属性中排除这些文件来实现。 2. 确保我们使用的是正确的构建命令。在命令行或脚本中,我们应该使用 "ng build" 命令来构建我们的Angular项目,并确保在构建过程中自动排除非JS模块文件。例如,我们可以使用以下命令构建项目: ``` ng build --prod ``` 3. 删除任何已经存在的非JS模块文件,以避免将其错误地部署到服务器上。通常,这些文件可以在Angular项目的 "src" 目录中找到,并且可能以 ".css", ".html" 或 ".json" 结尾。 4. 部署我们的ASP.NET Core Angular项目到IIS。可以通过将项目文件复制到IIS网站目录中或使用自动化工具(例如Web Deploy)进行部署来实现。确保将ASP.NET Core应用程序部署为网站的子目录,以便正确配置IIS的应用程序池。 通过按照上述步骤进行操作,我们应该能够成功地将ASP.NET Core Angular项目部署到IIS上并解决"non-js module files deprecated"的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值