我已经设置了一个支持FILESTREAM的SQL数据库,并尝试使用SqlFileStream通过WebAPI将从数据库中检索到的文件流式传输到浏览器。
由于某种原因,它不起作用,但我没有得到正确的错误消息。浏览器只是中止连接,Fiddler也没有显示任何有用的东西,并且VS中似乎没有出现任何错误。
public HttpResponseMessage Get(Guid id)
{
if(id == null || id == Guid.Empty)
return Request.CreateResponse(HttpStatusCode.BadRequest);
try
{
FileStreamContext fsc = null;
Document document = null;
using(var transaction = new TransactionScope())
using (var db = new MyEntities())
{
try
{
fsc = db.Database.SqlQuery<FileStreamContext>("SELECT [File].PathName() AS InternalPath, GET_FILESTREAM_TRANSACTION_CONTEXT() AS TransactionContext FROM Document WHERE id={0}", id).First();
}
catch (Exception e)
{
Debug.Print(e.ToString());
}
document = db.Documents.Where(doc => doc.ID == id).Single();
var fileStream = new SqlFileStream(fsc.InternalPath, fsc.TransactionContext, FileAccess.Read);
HttpResponseMessage response = new HttpResponseMessage();
response.Content = new StreamContent(fileStream);
//response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
//response.Content.Headers.ContentDisposition.FileName = document.FileName;
response.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(document.ContentType);
return response;
}
}
catch (Exception e)
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
}
我怀疑TransactionScope提前关闭可能会出现问题?不知道为什么我没有收到任何错误消息。
通过WebApi流式传输SqlFileStream的正确方法是什么?
答案 0 :(得分:0)
您是否尝试阅读控制器中的StreamContent
,将其放入fileStream
数组,然后使用{{{}设置内容,而不是将内容设置为byte
。 1}}?
ByteArrayContent
对于我已使用的var fileStream = new SqlFileStream(fsc.InternalPath, fsc.TransactionContext, FileAccess.Read);
byte[] fileContent = fileStream.ReadFully(); // you will need to implement ReadFully
HttpResponseMessage response = new HttpResponseMessage();
response.Content = new ByteArrayContent(fileContent);
实施,here is a link to a Jon Skeet method。
我怀疑你过早关闭连接是正确的。您已将ReadFully
/ DbContext
很好地包裹在ObjectContext
块中,但我认为这是问题所在。在控制器返回using
之后,该上下文正在处理,但响应只能访问流 - 它仍然需要读取流并将其转换为HttpResponseMessage
,然后再返回浏览器或客户。当您使用byte[]
等时,这通常会自动发生,因为框架仍然可以访问流来读取其内容。但在这种情况下,您可以在读取流之前处置SQL连接。
另一个解决方案可能是为MemoryStream
使用依赖注入,而不是在action方法中新建它。如果您将IoC容器设置为在HTTP请求结束时自动处理上下文,那么当框架将DbContext
转换为StreamContent
时,它仍应可用(不存在)把它推回网络。