Per un progetto MVC asp.Net, avrò bisogno di gestire file di grandi dimensioni (principalmente 200-300 mo, a volte 1 go).Applicazione sovrapposta: Archivia file in filestream nel database
Li memorizzerò nel database (per motivi di backup/motivo di coerenza).
Sono preoccupato per il problema di prestazioni, quindi voglio evitare tutto il possibile per avere una serie di byte in qualsiasi punto del programma, l'obiettivo è quindi quello di lavorare con streaming ovunque.
Ho un'applicazione a livelli, che significa principalmente che ho diversi "DataStore", che sono responsabili per la connessione e il recupero/inserimento/aggiornamento dei dati dal database.
Poiché EF non supporta Filestream per ora, sto gestendo la "parte del file" tramite semplici richieste Sql. Ho letto un buon articolo su utilizzo filestream qui: http://blog.tallan.com/2011/08/22/using-sqlfilestream-with-c-to-access-sql-server-filestream-data/
E ho alcune domande supplementari, che spero che mi può aiutare/punto me il buon senso:
- dal momento che ho un'applicazione a livelli, una volta che ho istanziato il mio oggetto SQLFileStream, potrei disporre di SqlCommand/Sql Connection/Transaction scope?
- In caso contrario, come dovrei chiuderli?
- Nel collegamento precedente, c'è un esempio che mostra come usarlo con ASP. Ma dal momento che sto usando ASP.Net MVC, non c'è un helper che sia direttamente in grado di trasmettere un file al browser? Perché ho trovato molti esempi di dati binari di ritorno al browser, ma per ora, tutti gli esempi che ho trovato rendono fondamentalmente qualcosa come
Stream.ToArray()
per riempire un array di byte e restituirlo al browser. Ho scoperto che posso restituire unFileStreamResult
che può contenere un parametro aStream
. È la giusta direzione?
(io non sto attualmente preoccupazione per il caricamento di file di grandi dimensioni, dal momento che vengono inseriti da un client pesante nel database)
EDIT
(Ci scusiamo per il codice sporca, è solo per non avere qui 50 metodi diversi. Ho fatto qualche altro tentativo e attualmente sono bloccato con la parte "letta", a causa della parte separata (dove generiamo il livello e dove lo consumiamo):
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);
Ma ottengo un'eccezione a rdr.GetSqlBinary(1).Value
perché GET_FILESTREAM_TRANSACTION_CONTEXT restituisce null. Ho trovato here che questo è dovuto alla transazione mancante.
Ho provato con un "TransactionScope" + la sua chiamata .Complete();
. Non cambia nulla
ho cercato di fare un BEGIN TRANSACTION, come mostrato nel link precedente:
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();
Ma si blocca sul primo "ExecuteNonQuery" con il eccezione "A transaction that was started in a MARS batch is still active at the end of the batch. The transaction is rolled back."
Ma è la prima query eseguita!
Direi che questo è un compito più adatto ai file system, dal momento che si tratta di file. Supponendo che il sito/database sia distribuito su una macchina Windows, un'alternativa da considerare potrebbe essere Transactional NTFS. Dovrebbe anche integrarsi con altre transazioni usando il DTM. Ovviamente ci sono alcuni gotcha lì (ad esempio, supporto per la condivisione di file non valido). +1 per non utilizzare il byte [] :) –