繁体   English   中英

在ASP.NET Core中流式处理IEnumerable

[英]Streaming and disposing an IEnumerable in ASP.NET core

我正在尝试在ASP.NET核心中实现一个控制器,该控制器返回从SQL数据库查询的潜在大量数据。 为此,我通过Dapper的Query()方法使用buffered:false参数执行查询。 这意味着在枚举查询结果之后必须处置SqlConnection对象。

似乎没有一个简单的方法来实现这一目标。 我通过编写一个包装IEnumerable的类使它起作用,并且引用计数了要求创建的任何Enumerator。 处置所有枚举器后,它将处置数据库连接。

这似乎可行,但是我担心在某些情况下无法处理数据库连接(例如,如果请求在开始枚举查询结果之前被取消了)。 是否有更好的方法,只需写入临时文件并将其流式传输到客户端?

这就是我最后想出的。 连接的生存期由StreamedDatabaseObjectResult拥有,它代替通常的ObjectResult返回。 存储库类返回要处置的连接以及结果。 这似乎涵盖了所有情况,并且可以很好地与异步方法配合使用。

public class StreamedDatabaseObjectResult : ActionResult
{
    private readonly Func<Task<DisposableEnumerable>> _getValuesFunc;

    public StreamedDatabaseObjectResult(Func<Task<DisposableEnumerable>> getValuesFunc)
    {
        _getValuesFunc = getValuesFunc;
    }

    public override async Task ExecuteResultAsync(ActionContext context)
    {
        using (var de = await _getValuesFunc())
        {
            var objectResult = new ObjectResult(de.Values);
            await objectResult.ExecuteResultAsync(context);
        }
    }
}

public class DisposableEnumerable : IDisposable
{
    public IEnumerable Values { get; }
    private readonly IDisposable _disposable;

    public DisposableEnumerable(IDisposable disposable, IEnumerable values)
    {
        Values = values;
        _disposable = disposable;
    }

    /// <inheritdoc />
    public void Dispose()
    {
        _disposable.Dispose();
    }
}

[HttpGet]
[ProducesResponseType(200)]
public ActionResult<IEnumerable<MyClass>> GetThings(CancellationToken cancellationToken)
{
    return new StreamedDatabaseObjectResult(() => _repo.GetThings(cancellationToken));
}

暂无
暂无

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

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