在不关闭底层流的情况下安全地使用带有 HttpContent.ReadAsStreamAsync() 的 StreamReader
Posted
技术标签:
【中文标题】在不关闭底层流的情况下安全地使用带有 HttpContent.ReadAsStreamAsync() 的 StreamReader【英文标题】:Safely using a StreamReader with HttpContent.ReadAsStreamAsync() without closing the underlying stream 【发布时间】:2019-11-04 17:10:22 【问题描述】:我有多个属性类需要访问HttpContent
(位于HttpActionContext
的HttpRequstMessage
中)中的数据,但我在决定最佳方法时遇到问题。我考虑在HttpContent
上使用ReadAsStringAsync
方法,但似乎我需要访问Stream
才能首先将位置设置为0。
天真的方法似乎只是用using
语句将StreamReader
包裹在基本流周围,如下所示:
public override void OnActionExecuting(HttpActionContext actionContext)
string rawJson;
using (StreamReader streamReader = new StreamReader(actionContext.Request.Content.ReadAsStreamAsync().Result))
streamReader.BaseStream.Position = 0;
rawJson = streamReader.ReadToEnd();
// etc
这适用于第一个执行的属性,但每个后续执行的属性都会在 actionContext.Request.Content.ReadAsStreamAsync()
上引发异常,因为它已被释放。
这里有一些可行的替代方法,但我真的很想知道这样做的最佳方法。
1:将StreamReader
包裹在基本流周围,永远不要丢弃它。
public override void OnActionExecuting(HttpActionContext actionContext)
StreamReader streamReader = new StreamReader(actionContext.Request.Content.ReadAsStreamAsync().Result);
streamReader.BaseStream.Position = 0;
string rawJson = streamReader.ReadToEnd();
// etc
这适用于每个属性,但我担心我可能会因为不释放 StreamReader
而导致内存泄漏。
2:将基本流复制到 MemoryStream
并用 StreamReader
包装。
public override void OnActionExecuting(HttpActionContext actionContext)
MemoryStream memoryStream = new MemoryStream();
Stream s = actionContext.Request.Content.ReadAsStreamAsync().Result;
s.Position = 0;
s.CopyTo(memoryStream);
string rawJson;
using (StreamReader streamReader = new StreamReader(memoryStream))
streamReader.BaseStream.Position = 0;
rawJson = streamReader.ReadToEnd();
// etc
这适用于每个属性,但代码量很大,可能效率低下。
3:将基本流的位置设置为0,然后调用ReadAsStringAsync
。
public override void OnActionExecuting(HttpActionContext actionContext)
actionContext.Request.Content.ReadAsStreamAsync().Result.Position = 0;
string rawJson = actionContext.Request.Content.ReadAsStringAsync().Result;
// etc
这适用于每个属性,但可能效率较低。
那么,有没有一种不泄漏内存的最佳方法呢?
【问题讨论】:
【参考方案1】:使用使流保持打开状态的流阅读器 - 因为您不拥有流的所有权,它仍然在 HTTP 操作内容的范围内拥有。
public StreamReader (System.IO.Stream stream, System.Text.Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen);
Constructor with the option to leave the stream open
由于可能出现死锁,使用 .Result 在同步上下文中完成异步调用也是有风险的。尝试将您的方法重构为异步。
【讨论】:
以上是关于在不关闭底层流的情况下安全地使用带有 HttpContent.ReadAsStreamAsync() 的 StreamReader的主要内容,如果未能解决你的问题,请参考以下文章
我可以在不使用 javascript 的情况下从带有 href 或其他内容的 .html 文件调用 .java 文件吗[关闭]
如何在不使用 github 中的秘密的情况下安全地签署 Android apk?