5

I have images stored in my database in a FILESTREAM and I am trying to find out what the best solution is to get that image back out into a web browser.

If I was managing the files on the file system myself, the quickest way would just be:

Response.TransmitFile(pathToFile);

This does not load the file into memory before transmitting it back to the client (to my understanding) and as such is nice and speedy.

I'm currently using Linq to SQL to get the FILESTREAM. This provides the FILESTREAM as a Binary object.

So far have this quite ugly way of doing it:

Response.WriteBinary(fileStreamBinary.ToArray());

Am I going to be better off not bothering with the Linq to SQL and doing things more directly?

I'm beginning to wonder why I bothered with FILESTREAM in the first place and didn't just stick to managing the files myself. I'm sure there was a reason for it without using the word "bandwagon"!

joshcomley
  • 28,099
  • 24
  • 107
  • 147

3 Answers3

1

This does not load the file into memory before transmitting it back to the client (to my understanding) and as such is nice and speedy.

Correct, but remember to set Response.BufferOutput to false, the default value is true.

Am I going to be better off not bothering with the Linq to SQL and doing things more directly?

If you don't want to load the entire binary content into memory first then yes. Here's an example for streaming binary data from a database (along with enabling resumable download functionality).

I'm beginning to wonder why I bothered with FILESTREAM in the first place and didn't just stick to managing the files myself

The primary benefit is data integrity with transactional support and inclusion in database backups so you don't have to worry about disparity between database backup and file system backup. The downside has always been performance, which is what this whole filestream feature is trying to overcome. Although if they're less than 1mb on average according to this document it's actually faster stored in the database than in the file system.

In Sql Server 2012 there's a new feature coming called FileTables that builds on FileStream support. Basically it acts like a database view of a filesystem directory in that files added to that directory are automatically added to the database FileTable (is a fixed schema table, which contains a Filestream binary column for the file, that you can link to from other tables). This would then allow you to retrieve a path to the file that you can feed to your Response.TransmitFile(...) function, yet still benefit from sql Filestream support.

Community
  • 1
  • 1
Michael
  • 11,571
  • 4
  • 63
  • 61
1

What about that ?

byte[] buffer = new byte[bufferSize];
int nBytes;
while((nBytes = fileStreamBinary.Read(buffer, 0, bufferSize) != 0)
{
    Response.OutputStream.Write(buffer, 0, nBytes);
}

That way you never load the whole stream into memory

Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • Hmmm maybe we are talking about different Binary object types - Linq returns a System.Data.Linq.Binary object which does not have a Read() method :( – joshcomley Jun 06 '09 at 01:28
  • Sorry, I misunderstood your code sample and thought that fileStreamBinary was a stream... I'm not familiar with System.Data.Linq.Binary, but it seems to be fetching the whole buffer at once, so you can't avoid loading it in memory. So I'm afraid the code you find "ugly" is the only way... – Thomas Levesque Jun 06 '09 at 01:38
  • Looks like I may have to circumvent Linq when using FILESTREAM then. Seems silly seeing as the whole point of FILESTREAM was to allow super-quick direct-from-disk streaming! – joshcomley Jun 06 '09 at 01:40
  • You can probably do that by executing a SqlCommand on the DataContext.Connection, and retrieve the data with SqlDataReader.GetBytes – Thomas Levesque Jun 06 '09 at 02:22
  • @ThomasLevesque SqlFileStream is the SqlType designated for reading binary data stored using Filestream support. – Michael Feb 02 '12 at 11:02
  • @ThomasLevesque: Just that it's probably more optimal (quicker for large files) than SqlDataReader.GetBytes, or doesn't it really matter? – Michael Feb 03 '12 at 06:54
  • @Michael, to be honest I have no idea if it makes any difference ;) – Thomas Levesque Feb 03 '12 at 08:32
0

Basically the same idea as Thomas presented, but a bit more verbose. The buffering should be turned off and the data committed/flushed periodically to avoid buffering all incoming data before sending it to the client.

I am using similar code to stream data (in this case Pdf:s) from a Blob in a Database -> WCF Service (streaming) -> Client (Browser)

This is probably not the best approach for smaller items, but useful for transmitting stuff coming from some kind of stream.

Response.Clear();
Response.ContentType = "application/pdf";
Response.Buffer = false;

var buffer = new byte[BufferSize];
int bytesRead;
while ((bytesRead = inputStream.Read(buffer, 0, BufferSize)) != 0)
{
     if (!Response.IsClientConnected)
          break;

     Response.OutputStream.Write(buffer, 0, bytesRead);
     Response.Flush();
}
Jakob Möllås
  • 4,239
  • 3
  • 33
  • 61