Skip to content

Instantly share code, notes, and snippets.

@nerdpad
Created May 12, 2015 15:58
Show Gist options
  • Save nerdpad/6d9b399f2f5f5e5c6519 to your computer and use it in GitHub Desktop.
Save nerdpad/6d9b399f2f5f5e5c6519 to your computer and use it in GitHub Desktop.
This is a sample to recreate the issue posted on stackoverflow: http://goo.gl/U83sfn
USE master
GO
-- Enable FileStream at the Instance Level
EXEC sp_configure filestream_access_level, 2
RECONFIGURE
GO
-- Provide a FileStream Filegroup
-- Create Client DB Database
-- Enable Non-Transactional Access at the Database Level
IF NOT EXISTS (SELECT [name] FROM sys.databases WHERE [name] = 'ClientDB')
CREATE DATABASE ClientDB ON PRIMARY (NAME = ClientDB_data, FILENAME = 'C:\DB\ClientDB.mdf'),
FILEGROUP ClientDBFSGroup CONTAINS FILESTREAM (NAME = ClientDB_FS, FILENAME = 'C:\DB\ClientDBFileStream')
LOG ON (NAME = 'ClientDB_log', FILENAME = 'C:\DB\ClientDB_log.ldf')
WITH FILESTREAM (NON_TRANSACTED_ACCESS = FULL, DIRECTORY_NAME = N'ClientDBFS')
GO
USE ClientDB
GO
-- Create documents table
IF OBJECT_ID('Documents') IS NULL
CREATE TABLE Documents AS FileTable
GO
namespace Sample.FileDownloader
{
using System.Collections.Generic;
using System.Configuration;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.IO;
using System.Threading.Tasks;
using System.Transactions;
/// <summary>
/// A sample document
/// </summary>
public class Document
{
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>
/// The name.
/// </value>
public string Name { get; set; }
/// <summary>
/// Gets or sets the path.
/// </summary>
/// <value>
/// The path.
/// </value>
public string UNCPath { get; set; }
/// <summary>
/// Gets or sets the stream.
/// </summary>
/// <value>
/// The stream.
/// </value>
public byte[] Stream { get; set; }
}
/// <summary>
/// Sample file downloader
/// </summary>
public class FileDownloader
{
/// <summary>
/// The directory to dump all the files
/// </summary>
private const string DumpDirectory = "c:\\repo\\filedump";
/// <summary>
/// The connection string
/// </summary>
private static readonly string ConnectionString = ConfigurationManager.ConnectionStrings["ContentService"].ConnectionString;
/// <summary>
/// Starts this instance.
/// </summary>
/// <returns>Returns nothing</returns>
public async Task Start()
{
using (var ts = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
{
// Fetch all the files from table
var documents = await this.GetAllDocuments();
// download all the files to dump directory simultaneously
// Parallel.ForEach(documents, this.DumpFile);
var transaction = Transaction.Current;
Parallel.ForEach(
documents,
d =>
{
using (var t = transaction.DependentClone(DependentCloneOption.RollbackIfNotComplete))
{
this.DumpFile(d);
t.Complete();
}
});
ts.Complete();
}
}
/// <summary>
/// Gets all documents.
/// </summary>
/// <returns>return all documents</returns>
private async Task<List<Document>> GetAllDocuments()
{
const string CmdStr = "Select name, file_stream.PathName(1) as unc_path, GET_FILESTREAM_TRANSACTION_CONTEXT() as stream from Documents";
var result = new List<Document>();
using (var con = new SqlConnection(ConnectionString))
using (var cmd = new SqlCommand(CmdStr, con))
{
con.Open();
var reader = await cmd.ExecuteReaderAsync();
if (!reader.HasRows)
{
return result;
}
while (reader.Read())
{
result.Add(
new Document
{
Name = reader.GetString(reader.GetOrdinal("name")),
UNCPath = reader.GetString(reader.GetOrdinal("unc_path")),
Stream = reader.GetFieldValue<byte[]>(reader.GetOrdinal("stream"))
});
}
return result;
}
}
/// <summary>
/// Dumps the file.
/// </summary>
/// <param name="document">The document.</param>
private void DumpFile(Document document)
{
// open the stream and dump the file to the file system
using (var sqlStream = new SqlFileStream(document.UNCPath, document.Stream, FileAccess.Read, FileOptions.SequentialScan, 4096))
using (var fileStream = new FileStream(Path.Combine(DumpDirectory, document.Name), FileMode.CreateNew))
{
sqlStream.CopyTo(fileStream);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment