SQL 文件流中断
SQL FILESTREAM breaking
场景:我最近在我的 ASP.NET MVC 应用程序中添加了一个组件,允许他们将文件上传到数据库中。由于这些文件平均超过 2MB,我选择使用 FILESTREAM。我将 HttpPostedFileBase
保存到临时文件,执行一些业务逻辑,然后上传文件。上传后,用户将被重定向到浏览器内联查看文件的页面。这是相关的上传代码:
var DocContext = new DocumentEntities();
var dbFile = new File
{
DocumentID = Guid.NewGuid(),
Name = fileName,
Type = file.ContentType
};
DocContext.Document.Add(dbFile);
DocContext.SaveChanges();
using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
using (var sqlFS = dbFile.Open(DocContext, FileAccess.Write))
using (var tempFS = tempFile.OpenRead())
{
tempFS.CopyTo(sqlFS);
scope.Complete();
}
这里是相关的viewing/download代码:
public ActionResult File(Guid? id = null)
{
if (id == null)
return RedirectToActionPermanent("Index");
return File(DocContext.Document.Find(id.Value) as File);
}
private ActionResult File(File file)
{
if (file == null)
throw new HttpException(404, "Unknown document type");
var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead });
Disposing += d => { scope.Complete(); scope.Dispose(); };
var fs = file.Open(DocContext, FileAccess.Read);
Disposing += d => fs.Dispose();
return new Misc.InlineFileStreamResult(fs, file.MimeType) { FileDownloadName = file.FileName, Inline = true };
}
以及打开方法:
public partial class File
{
public SqlFileStream Open(DocumentEntities db, FileAccess access)
{
var path = db.Database.SqlQuery<string>(
@"SELECT FileData.PathName() FROM [File] WHERE DocumentID = @docID",
new SqlParameter("docID", DocumentID)).First();
var context = db.Database.SqlQuery<byte[]>(
@"SELECT Get_FILESTREAM_TRANSACTION_CONTEXT() FROM [File] WHERE DocumentID = @docID",
new SqlParameter("docID", DocumentID)).First();
return new SqlFileStream(path, context, access);
}
}
查看以前上传的文件效果很好。查看用户自己上传的文件(最近?),出现如下异常:
The transaction operation cannot be performed because there are pending requests working on this transaction.
怎么回事?
更新:我假设因为我是 SQL 系统管理员,所以我可以上传文件并查看它们。
当数据库条目在“类型”列中具有 MIME 类型而不是扩展名时,我使用 IIS 和 web.config 来推断为文件提供的扩展名。但是普通用户没有阅读 web.config 的权限。因此,当非服务器管理员用户试图查看以 MIME 类型而不是扩展名存储的文件时,我的例程会抛出权限异常,这会以某种方式触发事务操作异常。不知道怎么办。
场景:我最近在我的 ASP.NET MVC 应用程序中添加了一个组件,允许他们将文件上传到数据库中。由于这些文件平均超过 2MB,我选择使用 FILESTREAM。我将 HttpPostedFileBase
保存到临时文件,执行一些业务逻辑,然后上传文件。上传后,用户将被重定向到浏览器内联查看文件的页面。这是相关的上传代码:
var DocContext = new DocumentEntities();
var dbFile = new File
{
DocumentID = Guid.NewGuid(),
Name = fileName,
Type = file.ContentType
};
DocContext.Document.Add(dbFile);
DocContext.SaveChanges();
using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted }))
using (var sqlFS = dbFile.Open(DocContext, FileAccess.Write))
using (var tempFS = tempFile.OpenRead())
{
tempFS.CopyTo(sqlFS);
scope.Complete();
}
这里是相关的viewing/download代码:
public ActionResult File(Guid? id = null)
{
if (id == null)
return RedirectToActionPermanent("Index");
return File(DocContext.Document.Find(id.Value) as File);
}
private ActionResult File(File file)
{
if (file == null)
throw new HttpException(404, "Unknown document type");
var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { IsolationLevel = IsolationLevel.RepeatableRead });
Disposing += d => { scope.Complete(); scope.Dispose(); };
var fs = file.Open(DocContext, FileAccess.Read);
Disposing += d => fs.Dispose();
return new Misc.InlineFileStreamResult(fs, file.MimeType) { FileDownloadName = file.FileName, Inline = true };
}
以及打开方法:
public partial class File
{
public SqlFileStream Open(DocumentEntities db, FileAccess access)
{
var path = db.Database.SqlQuery<string>(
@"SELECT FileData.PathName() FROM [File] WHERE DocumentID = @docID",
new SqlParameter("docID", DocumentID)).First();
var context = db.Database.SqlQuery<byte[]>(
@"SELECT Get_FILESTREAM_TRANSACTION_CONTEXT() FROM [File] WHERE DocumentID = @docID",
new SqlParameter("docID", DocumentID)).First();
return new SqlFileStream(path, context, access);
}
}
查看以前上传的文件效果很好。查看用户自己上传的文件(最近?),出现如下异常:
The transaction operation cannot be performed because there are pending requests working on this transaction.
怎么回事?
更新:我假设因为我是 SQL 系统管理员,所以我可以上传文件并查看它们。
当数据库条目在“类型”列中具有 MIME 类型而不是扩展名时,我使用 IIS 和 web.config 来推断为文件提供的扩展名。但是普通用户没有阅读 web.config 的权限。因此,当非服务器管理员用户试图查看以 MIME 类型而不是扩展名存储的文件时,我的例程会抛出权限异常,这会以某种方式触发事务操作异常。不知道怎么办。