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

本文关键字:开始 传输 结果 JSON Net ASP Core 是否 | 更新日期: 2023-09-27 18:16:05

我使用的是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,是否可以开始流式传输JSON结果

所以我知道这个问题很老了,但这是非常可能的Asp。. Net Core 2.2(可能从更早的版本开始,自从IEnumerable<T>被支持作为操作的返回结果以来)

虽然我不完全熟悉postgres和DataReader,但功能是让它将结果流式传输到客户端。附加到一个列表,并返回整个结果会占用大量内存,这取决于结果的大小,而流可以帮助我们避免这种情况。

这是一个动作的例子,它返回一个IEnumerable<string>流到客户端(它被以块的形式发送,直到所有的东西都使用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中,你应该包含偏移量和限制的参数,以允许客户端以任何大小的块步进并检索结果集,你可以用它来决定什么看起来足够灵敏。然后在你的客户端,你需要一个ajax调用你的api的循环,可能使用jquery,并保持一个又一个页面的循环,将结果添加到客户端的绑定集合或创建ui元素,或其他,直到结果返回空。

或者,如果一次显示全部10k条记录不是必要的,您可以简单地对结果进行分页,并提供一个在页面中分步执行的接口。我用过的一个是Sakura在git hub上的:PagedList