gpt4 book ai didi

c# - JToken.WriteToAsync 不会写入 JsonWriter

转载 作者:行者123 更新时间:2023-12-02 01:16:42 30 4
gpt4 key购买 nike

我正在尝试创建一个以某种方式更改请求的中间件。我能够阅读它并更改内容,但我无法弄清楚如何正确设置流编写器来创建新的正文。当我调用 normalized.WriteToAsync(jsonWriter) 时,MemoryStream 保持为空,因此我收到 A non-empty request body is required. 异常。我在这里缺少什么?这是我到目前为止所拥有的:

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);
}

<小时/>

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; }
}

最佳答案

您需要正确刷新并关闭 JsonTextWriterStreamWriter 才能完全填充 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();
}
}

演示 fiddle #1 here .

或者,由于您正在写入 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);
}

演示 fiddle #2 here .

注释:

  • 注意 await using 的使用对于StreamWriter。此语法保证 StreamWriter 将被异步刷新和关闭,并且可以在任何实现 IAsyncDisposable 的对象上使用。 。 (只有当您写入文件流或其他非内存流时,这才真正重要。)

  • 似乎 JsonTextWriter 都没有也不是基类 JsonWriter实现 IAsyncDisposable,因此我必须手动异步关闭 JSON 编写器,而不是通过 using 语句。外部 await using 应确保底层 StreamWriter 在发生异常时不会保持打开状态。

  • JSON RFC 8259指定实现不得将字节顺序标记 (U+FEFF) 添加到网络传输的 JSON 文本的开头。因此,在构造StreamWriter时,建议传递诸如new UTF8Encoding(false)之类的编码。不预先添加 BOM。或者,如果您只需要 UTF-8,则 StreamWriter constructors如果您自己没有指定并为该参数保留默认值(如上面的代码所示),将创建一个不带字节顺序标记 (BOM) 的 UTF-8 编码的 StreamWriter。 p>

关于c# - JToken.WriteToAsync 不会写入 JsonWriter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60915876/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com