【发布时间】:2012-02-16 16:53:03
【问题描述】:
对于一个 asp.Net MVC 项目,我需要处理大文件(主要是 200-300Mo,有时是 1Go)。
我会将它们存储在数据库中(出于备份原因/一致性原因)。
我担心性能问题,所以我想尽可能避免在程序中的任何地方都有一个字节数组,目标是在每个地方都使用流。
我有一个分层应用程序,这主要意味着我有几个“DataStore”,它们负责连接和检索/插入/更新数据库中的数据。
由于 EF 目前不支持 Filestream,我通过简单的 Sql 请求处理“文件部分”。我在这里阅读了一篇关于文件流使用的好文章:http://blog.tallan.com/2011/08/22/using-sqlfilestream-with-c-to-access-sql-server-filestream-data/
我还有一些其他问题,希望您能帮助我/指出好的方向:
- 由于我有一个分层应用程序,一旦我实例化了我的 SQLFileStream 对象,我可以处置 SqlCommand/Sql Connection/Transaction 范围吗?
- 如果没有,我应该如何关闭它们?
- 在上一个链接中,有一个示例展示了如何将它与 ASP 一起使用。但是由于我使用的是 ASP.Net MVC,难道没有一个助手可以直接将文件流式传输到浏览器吗?因为我发现了很多将二进制数据返回到浏览器的示例,但是现在,我发现的所有示例基本上都类似于
Stream.ToArray()来填充字节数组并将其返回给浏览器。我发现我可以返回一个FileStreamResult,它可以接受参数Stream。这是正确的方向吗?
(我目前不关心上传大文件,因为它们是由数据库中的重型客户端插入的)
编辑
(对不起,脏代码,只是这里没有 50 种不同的方法。 我又做了一些尝试,但由于分离的部分(我们在哪里生成图层以及在哪里使用它),我目前被“读取”部分卡住了:
SqlConnection conn = GetConnection();
conn.Open();
SqlCommand cmd = new SqlCommand(_selectMetaDataRequest, conn);
cmd.Parameters.Add(_idFile, SqlDbType.Int).Value = idFile;
SqlDataReader rdr = cmd.ExecuteReader();
rdr.Read();
string serverPath = rdr.GetSqlString(0).Value;
byte[] serverTxn = rdr.GetSqlBinary(1).Value;
rdr.Close();
return new SqlFileStream(serverPath, serverTxn, FileAccess.Read);
但我在rdr.GetSqlBinary(1).Value 遇到异常,因为 GET_FILESTREAM_TRANSACTION_CONTEXT 返回 null。我发现here 这是由于缺少交易。
我尝试使用“TransactionScope”+它的.Complete(); 调用。不会改变任何东西。
我尝试像上一个链接中显示的那样进行 BEGIN TRANSACTION:
SqlConnection connection = GetConnection(); connection.Open(); SqlCommand cmd = new SqlCommand();
cmd.CommandText = "BEGIN TRANSACTION";
cmd.CommandType = CommandType.Text;
cmd.Connection = connection;
cmd.ExecuteNonQuery();
cmd = new SqlCommand(_selectMetaDataRequest, connection);
cmd.Parameters.Add(_idFile, SqlDbType.Int).Value = idFile;
SqlDataReader rdr = cmd.ExecuteReader();
rdr.Read();
string serverPath = rdr.GetSqlString(0).Value;
byte[] serverTxn = rdr.GetSqlBinary(1).Value;
rdr.Close();
SqlFileStream sqlFileStream = new SqlFileStream(serverPath, serverTxn, FileAccess.Read);
cmd = new SqlCommand(); cmd.CommandText = "COMMIT TRANSACTION"; cmd.CommandType = CommandType.Text; cmd.Connection = connection; cmd.ExecuteNonQuery();
但它在第一个“ExecuteNonQuery”时崩溃,但 "A transaction that was started in a MARS batch is still active at the end of the batch. The transaction is rolled back." 除外,但这是第一个执行的查询!
【问题讨论】:
-
我会说这是一项更适合文件系统的任务,因为您正在处理文件。假设站点/数据库部署在 Windows 机器上,可以查看的一种替代方法是事务性 NTFS。它甚至应该使用 DTM 与其他事务集成。诚然,那里有一些问题(例如,糟糕的文件共享支持)。 +1 不使用 byte[] :)
标签: c# asp.net asp.net-mvc stream filestream