从数据库中流数据-ASP.NET Core和SqlDataReader.GetStream()

问题描述 投票:2回答:1

[我试图将大对象从ASP.NET Core站点发送到数据库时,将它们从数据库中加载到内存中的情况降到最低,因为有时会碰到OutOfMemoryException

我以为我会流式传输。现在,根据我的研究,只要您在命令中指定了CommandBehavior.SequentialAccess,SQL Server就支持此功能。我认为如果要进行流传输,则可能会尽可能直接地进行流传输,因此我几乎将其直接从DataReader传输到ASP.NET MVC ActionResult

但是一旦FileStreamResult(隐藏在File()的调用中)完成执行,如何清理我的阅读器/命令?连接是由DI提供的,所以这不是问题,但是我在对GetDocumentStream()的调用中创建了读取器/命令。

我在MVC中注册了ActionFilterAttribute的子类,所以给了我一个我可以调用ActionFilterAttribute.OnResultExecuted()的入口点,但是除了我目前处理清理的逻辑之外,我对放置什么绝对不知道我的数据库事务和提交/回滚的内容(不包含在内,因为它并不重要)。

DataReader / Command之后是否有办法清除并仍然提供StreamFile()

public class DocumentsController : Controller
{
    private DocumentService documentService;

    public FilesController(DocumentService documentService)
    {
        this.documentService = documentService;
    }

    public IActionResult Stream(Guid id, string contentType = "application/octet-stream") // Defaults to octet-stream when unspecified
    {
        // Simple lookup by Id so that I can use it for the Name and ContentType below
        if(!(documentService.GetDocument(id)) is Document document) 
            return NotFound();

        var cd = new System.Net.Http.Headers.ContentDispositionHeaderValue("inline") {FileNameStar = document.DocumentName};
        Response.Headers.Add(Microsoft.Net.Http.Headers.HeaderNames.ContentDisposition, cd.ToString());

        return File(documentService.GetDocumentStream(id), document.ContentType ?? contentType);
    }

    /*
    public class Document
    {
        public Guid Id { get; set; }
        public string DocumentName { get; set; }
        public string ContentType { get; set; }
    }
    */
}

public class DocumentService
{
    private readonly DbConnection connection;

    public DocumentService(DbConnection connection)
    {
        this.connection = connection;
    }

    /* Other content omitted for brevity */

    public Stream GetDocumentStream(Guid documentId)
    {
        //Source table definition
        /*
            CREATE TABLE [dbo].[tblDocuments]
            (
                [DocumentId] [uniqueidentifier] NOT NULL,
                [ContentType] [varchar](100) NULL,
                [DocumentName] [varchar](100) NULL,
                [DocumentData] [varbinary](max) NULL
            CONSTRAINT [PK_DocumentId] PRIMARY KEY NONCLUSTERED ([DocumentID] ASC)
            )
            GO
         */

        const string query = "SELECT DocumentData FROM tblDocuments WHERE DocumentId = @documentId";

        //build up the command
        var command = connection.CreateCommand();
        command.CommandText = query;
        var parameter = command.CreateParameter();
        parameter.DbType = System.Data.DbType.Guid;
        parameter.ParameterName = "@documentId";
        parameter.Value = documentId;
        command.Parameters.Add(parameter);

        //Execute commmand with SequentialAccess to support streaming the data
        var reader = command.ExecuteReader(System.Data.CommandBehavior.SequentialAccess);

        if(reader.Read())
            return reader.GetStream(0);
        else
            return Stream.Null;
    }
}

我试图从ASP.NET Core站点将大对象发送到数据库时,最大程度地减少将它们从数据库加载到内存中的原因,因为有时会遇到OutOfMemoryException。我以为我会串流...

c# sql-server asp.net-core streaming sqldatareader
1个回答
0
投票

内部FileStreamResult一旦完成执行就丢弃所提供的流,因此您管理起来应该不是问题。

© www.soinside.com 2019 - 2024. All rights reserved.