ASP.NET Core读取Request.Body的正确方法(3)

public override string ReadToEnd() { ThrowIfDisposed(); CheckAsyncTaskInProgress(); // 调用ReadBuffer,然后从charBuffer中提取数据。 StringBuilder sb = new StringBuilder(_charLen - _charPos); do { //循环拼接读取内容 sb.Append(_charBuffer, _charPos, _charLen - _charPos); _charPos = _charLen; //读取buffer,这是核心操作 ReadBuffer(); } while (_charLen > 0); //返回读取内容 return sb.ToString(); }

通过这段源码我们了解到了这么个信息,一个是StreamReader的ReadToEnd其实本质是通过循环读取ReadBuffer然后通过StringBuilder去拼接读取的内容,核心是读取ReadBuffer方法,由于代码比较多,我们找到大致呈现一下核心操作[点击查看源码👈]

if (_checkPreamble) { //通过这里我们可以知道本质就是使用要读取的Stream里的Read方法 int len = _stream.Read(_byteBuffer, _bytePos, _byteBuffer.Length - _bytePos); if (len == 0) { if (_byteLen > 0) { _charLen += _decoder.GetChars(_byteBuffer, 0, _byteLen, _charBuffer, _charLen); _bytePos = _byteLen = 0; } return _charLen; } _byteLen += len; } else { //通过这里我们可以知道本质就是使用要读取的Stream里的Read方法 _byteLen = _stream.Read(_byteBuffer, 0, _byteBuffer.Length); if (_byteLen == 0) { return _charLen; } }

通过上面的代码我们可以了解到StreamReader其实是工具类,只是封装了对Stream的原始操作,简化我们的代码ReadToEnd方法本质是读取Stream的Read方法。接下来我们看一下ReadToEndAsync方法的具体实现[点击查看源码👈]

public override Task<string> ReadToEndAsync() { if (GetType() != typeof(StreamReader)) { return base.ReadToEndAsync(); } ThrowIfDisposed(); CheckAsyncTaskInProgress(); //本质是ReadToEndAsyncInternal方法 Task<string> task = ReadToEndAsyncInternal(); _asyncReadTask = task; return task; } private async Task<string> ReadToEndAsyncInternal() { //也是循环拼接读取的内容 StringBuilder sb = new StringBuilder(_charLen - _charPos); do { int tmpCharPos = _charPos; sb.Append(_charBuffer, tmpCharPos, _charLen - tmpCharPos); _charPos = _charLen; //核心操作是ReadBufferAsync方法 await ReadBufferAsync(CancellationToken.None).ConfigureAwait(false); } while (_charLen > 0); return sb.ToString(); }

通过这个我们可以看到核心操作是ReadBufferAsync方法,代码比较多我们同样看一下核心实现[点击查看源码👈]

byte[] tmpByteBuffer = _byteBuffer; //Stream赋值给tmpStream Stream tmpStream = _stream; if (_checkPreamble) { int tmpBytePos = _bytePos; //本质是调用Stream的ReadAsync方法 int len = await tmpStream.ReadAsync(new Memory<byte>(tmpByteBuffer, tmpBytePos, tmpByteBuffer.Length - tmpBytePos), cancellationToken).ConfigureAwait(false); if (len == 0) { if (_byteLen > 0) { _charLen += _decoder.GetChars(tmpByteBuffer, 0, _byteLen, _charBuffer, _charLen); _bytePos = 0; _byteLen = 0; } return _charLen; } _byteLen += len; } else { //本质是调用Stream的ReadAsync方法 _byteLen = await tmpStream.ReadAsync(new Memory<byte>(tmpByteBuffer), cancellationToken).ConfigureAwait(false); if (_byteLen == 0) { return _charLen; } }

通过上面代码我可以了解到StreamReader的本质就是读取Stream的包装,核心方法还是来自Stream本身。我们之所以大致介绍了StreamReader类,就是为了给大家呈现出StreamReader和Stream的关系,否则怕大家误解这波操作是StreamReader的里的实现,而不是Request.Body的问题,其实并不是这样的所有的一切都是指向Stream的Request的Body就是Stream这个大家可以自己查看一下,了解到这一步我们就可以继续了。

HttpRequest的Body

上面我们说到了Request的Body本质就是Stream,Stream本身是抽象类,所以Request.Body是Stream的实现类。默认情况下Request.Body的是HttpRequestStream的实例[点击查看源码👈],我们这里说了是默认,因为它是可以改变的,我们一会再说。我们从上面StreamReader的结论中得到ReadToEnd本质还是调用的Stream的Read方法,即这里的HttpRequestStream的Read方法,我们来看一下具体实现[]

public override int Read(byte[] buffer, int offset, int count) { //知道同步读取Body为啥报错了吧 if (!_bodyControl.AllowSynchronousIO) { throw new InvalidOperationException(CoreStrings.SynchronousReadsDisallowed); } //本质是调用ReadAsync return ReadAsync(buffer, offset, count).GetAwaiter().GetResult(); }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyfdwg.html