簡體   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