我正在尝试创建一个以某种方式更改请求的中间件。我能够阅读它并更改内容,但我无法弄清楚如何正确设置流编写器来创建新的正文。当我打电话时normalized.WriteToAsync(jsonWriter)
the MemoryStream
仍然是空的,因此我收到需要一个非空的请求正文。例外。我在这里缺少什么?这是我到目前为止所拥有的:
public async Task Invoke(HttpContext context)
{
if (context.Request.ContentType == "application/json" && context.Request.ContentLength > 0)
{
using var scope = _logger.BeginScope("NormalizeJson");
try
{
using var requestReader = new HttpRequestStreamReader(context.Request.Body, Encoding.UTF8);
using var jsonReader = new JsonTextReader(requestReader);
var json = await JToken.LoadAsync(jsonReader);
var normalized = _normalize.Visit(json); // <-- Modify json and return JToken
// Create new Body
var memoryStream = new MemoryStream();
var requestWriter = new StreamWriter(memoryStream);
var jsonWriter = new JsonTextWriter(requestWriter);
await normalized.WriteToAsync(jsonWriter); // <-- At this point the MemoryStream has still 0 length.
var content = new StreamContent(memoryStream.Rewind()); // <-- Use helper extension to Seek.Begin = 0
context.Request.Body = await content.ReadAsStreamAsync();
}
catch (Exception e)
{
_logger.Scope().Exceptions.Push(e);
}
}
await _next(context);
}
Demo对于 LINQPad 等:
async Task Main()
{
var token = JToken.FromObject(new User { Name = "Bob" });
var memoryStream = new MemoryStream();
var requestWriter = new StreamWriter(memoryStream);
var jsonWriter = new JsonTextWriter(requestWriter);
await token.WriteToAsync(jsonWriter);
memoryStream.Length.Dump(); // <-- MemoryStream.Length = 0
}
public class User
{
public string Name { get; set; }
}
您需要正确冲洗并关闭您的JsonTextWriter
and StreamWriter
为了充分填充memoryStream
,像这样:
var memoryStream = new MemoryStream();
// StreamWriter implements IAsyncDisposable
// Leave the underlying stream open
await using (var requestWriter = new StreamWriter(memoryStream, leaveOpen: true))
{
var jsonWriter = new JsonTextWriter(requestWriter); // But JsonTextWriter does not implement IAsyncDisposable, only IDisposable!
try
{
await token.WriteToAsync(jsonWriter);
}
finally
{
await jsonWriter.CloseAsync();
}
}
演示小提琴#1here.
或者,既然您正在写信给MemoryStream
,确实没必要用async
根本没有,相反你可以这样做:
var memoryStream = new MemoryStream();
using (var requestWriter = new StreamWriter(memoryStream, leaveOpen: true)) // Leave the underlying stream open
using (var jsonWriter = new JsonTextWriter(requestWriter))
{
token.WriteTo(jsonWriter);
}
演示小提琴#2here.
Notes:
-
注意使用await using为了StreamWriter
。该语法保证StreamWriter
将被异步刷新和关闭,并且可以用于任何实现IAsyncDisposable。 (只有当您写入文件流或其他非内存流时,这才真正重要。)
-
似乎两者都不是JsonTextWriter也不是基类JsonWriter实施IAsyncDisposable
,所以我必须手动异步关闭 JSON writer,而不是通过using
陈述。外层await using
应确保底层StreamWriter
发生异常时不会保持打开状态。
-
JSON RFC 8259指定实现不得将字节顺序标记 (U+FEFF) 添加到网络传输的 JSON 文本的开头。因此,当构造一个StreamWriter
,建议传递一个编码,例如new UTF8Encoding(false)不预先添加 BOM。或者,如果您只需要 UTF-8,则StreamWriter构造函数 will 使用 UTF-8 编码创建一个不带字节顺序标记 (BOM) 的 StreamWriter如果您自己不指定参数并保留该参数的默认值,如上面的代码所示。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)