繁体   English   中英

在 ASP.Net Core 中,是否可以开始流式传输 JSON 结果?

[英]In ASP.Net Core, is it possible to start streaming JSON results?

我正在使用 ASP.Net Core WebAPI。

我有一种方法可以一次从数据库中检索 10000 个结果,但我注意到“等待”需要 1.17 秒,实际传输需要 0.3 秒(基于 Chrome 的网络图)。

将来自数据库(postgres)的结果通过 DataReader 进行迭代并转换为结构体,添加到列表中,最终作为 JsonResult 返回。

我不知道对选项的确切期望,但我希望能够尽快开始返回以降低总请求。 我也是第一次在这个平台上这样做,所以我可能没有以最好的方式做事。

    [HttpGet("{turbine:int}")]
    public IActionResult GetBearingTemperature(int turbine)
    {
        using (var connection = Database.GetConnection())
        {
            connection.Open();

            int? page = GetPage();

            var command = connection.CreateCommand();

            if (page.HasValue)
            {
                command.CommandText = @"select turbine, timestamp, mainbearingtemperature from readings where turbine = :turbine limit 10000 offset :offset;";
                command.Parameters.AddWithValue("offset", NpgsqlTypes.NpgsqlDbType.Integer, page.Value * 10000);
            } else
            {
                command.CommandText = @"select turbine, timestamp, mainbearingtemperature from readings where turbine = :turbine limit 10000;";
            }

            command.Parameters.AddWithValue("turbine", NpgsqlTypes.NpgsqlDbType.Integer, 4, turbine);                

            var reader = command.ExecuteReader();

            var collection = new List<BearingTemperature>();

            if (reader.HasRows)
            {
                var bt = new BearingTemperature();

                while (reader.Read())
                {                        
                    bt.Time = reader.GetDateTime(1);
                    bt.Turbine = reader.GetInt32(0);
                    bt.Value = reader.GetDouble(2);

                    collection.Add(bt);
                }

                return new JsonResult(collection);
            }
            else
            {
                return new EmptyResult();
            }

        }
    }

    private int? GetPage()
    {
        if (Request.Query.ContainsKey("page"))
        {
            return int.Parse(Request.Query["page"]);
        }
        else return null;

    }

    struct BearingTemperature
    {
        public int Turbine;
        public DateTime Time;
        public double Value;
    }

所以我知道这个问题很老,但这在 Asp.Net Core 2.2 中很有可能(甚至可能来自早期版本,因为IEnumerable<T>被支持作为操作的返回结果)。

虽然我对 postgres 和 DataReader 并不完全熟悉,但该功能可以将结果流式传输到客户端。 根据结果​​的大小,追加到列表并返回整个结果会占用大量内存,而流媒体可以帮助我们避免这种情况。

这是一个操作示例,它返回一个IEnumerable<string>流到客户端(它以块的形式发送,直到使用Transfer-Encoding: chunked标头Transfer-Encoding: chunked所有内容为止)。

[HttpGet]
public IEnumerable<string> Get()
{
    return GetStringsFor(10000);
}

private static readonly Random random = new Random();
private IEnumerable<string> GetStringsFor(int amount)
{
    const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    while (amount-- > 0)
    {
        yield return new string(Enumerable.Repeat(chars, random.Next(1000)).Select(s => s[random.Next(s.Length)]).ToArray());
    }
}

这将确保不是所有内容都加载到内存中,而是按需发送。 当您将数据读入内存时,您将能够在您的情况下实现类似的东西,因为这是系统可以开始发送结果的一次。

private IEnumerable<BearingTemperature> ReadTemperatures(SqlDataReader reader)
{
    if (reader.HasRows)
    {
        var bt = new BearingTemperature();

        while (reader.Read())
        {
            bt.Time = reader.GetDateTime(1);
            bt.Turbine = reader.GetInt32(0);
            bt.Value = reader.GetDouble(2);

            yield return bt;
        }
    }

    yield break;
}

[HttpGet("{turbine:int}")]
public IEnumerable<BearingTemperature> GetBearingTemperature(int turbine)
{
    using (var connection = Database.GetConnection())
    {
        <snip>

        var reader = command.ExecuteReader();
        return ReadTemperatures(reader);
    }
}

考虑到您的数据库将执行查询并返回整个结果集,您不可能流式传输部分结果集(尽管您可以在 google 流数据库中搜索其他产品)。 您可以做的是使用分页技术与 ajax 相结合来检索总结果集的切片,并将它们组合在客户端上,以保持高响应度并创建流式查询结果的错觉。

您需要查看OFFSETLIMIT子句

在您的 api 上,您将包含 offset 和 limit 的参数,以允许客户端逐步执行并以它想要的任何大小块检索结果集,您可以使用它来确定哪些看起来响应足够快。 然后在您的客户端上,您将需要对 api 的 ajax 调用进行循环,可能使用 jquery,并不断循环页面将结果添加到客户端上的绑定集合或创建 ui 元素或其他任何内容,直到结果空着回来。

或者,如果不需要一次显示整个 10k 记录,您可以简单地对结果进行分页并提供一个界面来逐步浏览这些页面。 我用于此目的的一个来自 git hub 上的 Sakura: PagedList

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM