[我试图将大对象从ASP.NET Core站点发送到数据库时,将它们从数据库中加载到内存中的情况降到最低,因为有时会碰到OutOfMemoryException
。
我以为我会流式传输。现在,根据我的研究,只要您在命令中指定了CommandBehavior.SequentialAccess
,SQL Server就支持此功能。我认为如果要进行流传输,则可能会尽可能直接地进行流传输,因此我几乎将其直接从DataReader
传输到ASP.NET MVC ActionResult
。
但是一旦FileStreamResult
(隐藏在File()
的调用中)完成执行,如何清理我的阅读器/命令?连接是由DI提供的,所以这不是问题,但是我在对GetDocumentStream()
的调用中创建了读取器/命令。
我在MVC中注册了ActionFilterAttribute
的子类,所以给了我一个我可以调用ActionFilterAttribute.OnResultExecuted()
的入口点,但是除了我目前处理清理的逻辑之外,我对放置什么绝对不知道我的数据库事务和提交/回滚的内容(不包含在内,因为它并不重要)。
DataReader
/ Command
之后是否有办法清除并仍然提供Stream
到File()
?
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。我以为我会串流...
内部FileStreamResult
一旦完成执行就丢弃所提供的流,因此您管理起来应该不是问题。