2016-02-12 1 views
0

Обучение и тестирование с использованием Sql FILESTREAM для веб-приложения. Клиент загружает большую файловую форму с веб-страницы, которая занимает время «X», и когда полная загрузка показывает 100% завершение. Тем не менее, очень большие файлы также требуют времени для SqlFileStream для записи в файловую систему, поэтому я хочу открутить поток, чтобы завершить эту часть. Код, который у меня есть, кажется, работает нормально, но никакие данные не попадают в файл filestream.SqlFileStream запись в отдельной теме не работает

Я обматываю создание первоначальной записи в своей собственной области транзакции и использую отдельную область транзакции в потоке. В потоковой подпрограмме у меня есть соответствующие PathName() и TransactionContext, но я предполагаю, что я пропускаю что-то при использовании потока.

Я прокомментировал обычный вызов SqlFileStream, который работает нормально. Вы видите что-то не так с тем, что я здесь делаю?

Public Function StoreFileStream() 
     Dim json As New Dictionary(Of String, Object) 
     Dim parms As New FileStreamThreadParameters 

     If HttpContext.Current.Request.Files.Count > 0 Then 
      Dim file As HttpPostedFile = HttpContext.Current.Request.Files(0) 

      If "contentType" <> String.Empty Then 
       Dim fs As Stream = file.InputStream 
       Dim br As New BinaryReader(fs) 
       Dim noBytes As New Byte() 

       Try 
        Dim filePath As String = "" 
        Dim trxContext As Byte() = {} 
        Dim baseFileId As Integer 

        Using trxScope As New TransactionScope 
         Using dbConn As New SqlConnection(DigsConnStr) 
          Using dbCmd As New SqlCommand("ADD_FileStreamFile", dbConn) 
           dbConn.Open() 
           Using dbRdr As SqlDataReader = dbCmd.ExecuteReader(CommandBehavior.SingleRow) 
            dbRdr.Read() 
            If dbRdr.HasRows Then 
             filePath = dbRdr("Path") 
             trxContext = dbRdr("TrxContext") 
             baseFileId = dbRdr("BaseFileID") 
            End If 
            dbRdr.Close() 
           End Using 

           ' Code below writes to file, but trying to offload this to a separate thread so user is not waiting 
           'Using dest As New SqlFileStream(filePath, trxContext, FileAccess.Write) 
           ' fs.CopyTo(dest, 4096) 
           ' dest.Close() 
           'End Using 
          End Using 
          dbConn.Close() 
         End Using 
         trxScope.Complete() 
        End Using ' transaction commits here, not in line above 

        parms.baseFileId = baseFileId 
        parms.fs = New MemoryStream 
        fs.CopyTo(parms.fs) 

        Dim fileUpdateThread As New Threading.Thread(Sub() 
                    UpdateFileStreamThreaded(parms) 
                   End Sub) 
        fileUpdateThread.Start() 

        json.Add("status", "success") 
       Catch ex As Exception 
        Elmah.ErrorSignal.FromCurrentContext().Raise(ex) 
        json.Add("status", "failure") 
        json.Add("msg", ex.Message) 
        json.Add("procedure", System.Reflection.MethodBase.GetCurrentMethod.Name) 
       End Try 
      Else 
       json.Add("status", "failure") 
       json.Add("msg", "Invalid file type") 
       json.Add("procedure", System.Reflection.MethodBase.GetCurrentMethod.Name) 
      End If 
     End If 
     Return json 
    End Function 

    Public Class FileStreamThreadParameters 
     Public Property baseFileId As Integer 
     Public fs As Stream 
    End Class 

    Private Sub UpdateFileStreamThreaded(parms As FileStreamThreadParameters) 
     Dim filePath As String = "" 
     Dim trxContext As Byte() = {} 

     Try 
      Using trxScope As New TransactionScope 
       Using dbConn As New SqlConnection(DigsConnStr) 
        Using dbCmd As New SqlCommand("SELECT FileBytes.PathName() 'Path', GET_FILESTREAM_TRANSACTION_CONTEXT() 'TrxContext' FROM FileStreamFile WHERE Id = " & parms.baseFileId, dbConn) 
         dbConn.Open() 
         Using dbRdr As SqlDataReader = dbCmd.ExecuteReader(CommandBehavior.SingleRow) 
          dbRdr.Read() 
          If dbRdr.HasRows Then 
           filePath = dbRdr("Path") 
           trxContext = dbRdr("TrxContext") 
          End If 
          dbRdr.Close() 

          Using dest As New SqlFileStream(filePath, trxContext, FileAccess.Write) 
           parms.fs.CopyTo(dest, 4096) 
           dest.Close() 
          End Using 
         End Using 
        End Using 
        dbConn.Close() 
       End Using 
       trxScope.Complete() 
      End Using 
     Catch ex As Exception 
      'Elmah.ErrorSignal.FromCurrentContext().Raise(ex) 
     End Try 
    End Sub 

ответ

0

Очевидно, что это сложная проблема. Я действительно получил его для работы с кодом ниже. Однако в конечном итоге я отказался от использования SQL FILESTREAM из-за слишком большой сложности при настройке.

Это существующее веб-приложение с сервером sql в другой коробке. После того, как я начал работать, следующим препятствием стала установка подлинности. Filestream требует встроенной безопасности в вашей строке подключения. Даже при проверке подлинности Windows в нашем приложении Intranet я не мог заставить веб-приложение использовать учетные данные Windows при подключении к базе данных. Кажется, что он использовал имя компьютера или службу пула приложений. Я попробовал много примеров, которые я нашел в сети, и здесь безрезультатно. Даже если у меня это получилось, тогда я бы хотел использовать группу Active Directory для отдельных логинов, которые выглядели как еще одно препятствие.

Это приложение хранит документы в столбце varbinary, чтобы в любой момент можно было включить полнотекстовый поиск. Проблема заключалась в больших файлах, которые обычно представляют собой изображения или видео. Поскольку вы не можете искать текст на них в любом случае, стратегия теперь заключается в том, чтобы хранить файлы в файловой системе, и все остальные документы, доступные для поиска (.docx, .pptx и т. Д.), Все равно будут храниться в varbinary. Мне действительно грустно, что я не могу заставить filestream работать, поскольку это похоже на идеальное решение. Я вернусь к нему однажды, но это действительно не должно быть так сложно. :-(

код, который я начала работать в:

    Dim filePath As String = "" 
        Dim trxContext As Byte() = {} 
        Dim baseFileId As Integer 

        Using trxScope As New TransactionScope 
         Using dbConn As New SqlConnection(DigsFSConnStr) 
          Using dbCmd As New SqlCommand("NEW_FileStreamBaseFile", dbConn) 
           dbCmd.CommandType = CommandType.StoredProcedure 
           dbCmd.Parameters.AddWithValue("@Title", fileDesc) 
           dbCmd.Parameters.AddWithValue("@Summary", summary) 
           dbCmd.Parameters.AddWithValue("@Comments", comments) 
           dbCmd.Parameters.AddWithValue("@FileName", uploadedFileName) 
           dbCmd.Parameters.AddWithValue("@ContentType", contentType) 
           dbCmd.Parameters.AddWithValue("@FileExt", ext) 
           'dbCmd.Parameters.AddWithValue("@FileBytes", noBytes) ' now that were offloading the file byte storage to a thread 
           dbCmd.Parameters.AddWithValue("@UploadedByResourceID", uploadedByResourceID) 
           dbCmd.Parameters.AddWithValue("@UploadedByShortName", uploadedByShortName) 
           dbCmd.Parameters.AddWithValue("@FileAuthor", fileAuthor) 
           dbCmd.Parameters.AddWithValue("@TagRecID", tagRecID) 
           dbCmd.Parameters.AddWithValue("@UserID", samAccountName) 
           dbCmd.Parameters.AddWithValue("@FileDate", fileDate) 
           dbCmd.Parameters.AddWithValue("@FileType", fileType) 
           dbCmd.Parameters.AddWithValue("@FileTypeRecID", fileTypeRecId) 

           ' Save to file system too for xod conversion 
           file.SaveAs(HttpContext.Current.Server.MapPath("~/files/uploaded/") & uploadedFileName) 

           dbConn.Open() 
           Using dbRdr As SqlDataReader = dbCmd.ExecuteReader(CommandBehavior.SingleRow) 
            dbRdr.Read() 
            If dbRdr.HasRows Then 
             filePath = dbRdr("Path") 
             trxContext = dbRdr("TrxContext") 
             json.Add("baseFileId", dbRdr("BaseFileID")) 
             virtualFileRecId = dbRdr("VirtualFileRecID") 
             dbStatus = dbRdr("status") 
             If dbStatus = "failure" Then 
              json.Add("msg", dbRdr("msg")) 
             End If 
            End If 
            dbRdr.Close() 
           End Using 

           ' Prepare and start Task thread to write the file 
           If dbStatus = "success" Then 
            bytes = br.ReadBytes(fs.Length) 
            Dim task As New System.Threading.Tasks.Task(
             Sub() 
              UpdateNewFileStreamBytes(virtualFileRecId, bytes) 
             End Sub) 
            task.Start() 
            json.Add("status", "success") 
           Else 
            json.Add("status", "failure") 
           End If 
          End Using 
          dbConn.Close() 
         End Using 
         trxScope.Complete() 
        End Using ' transaction commits here, not in line above 

С процедурой задача:

Private Sub UpdateNewFileStreamBytes(virtualFileRecId As Integer, fileBytes As Byte()) 
     Dim filePath As String = "" 
     Dim trxContext As Byte() = {} 

     Try 
      Using trxScope As New TransactionScope 
       Using dbConn As New SqlConnection(DigsFSConnStr) 
        Using dbCmd As New SqlCommand("UPD_FileStreamBaseFile", dbConn) 
         dbCmd.CommandType = CommandType.StoredProcedure 
         dbCmd.Parameters.AddWithValue("@VirtualFileRecID", virtualFileRecId) 

         dbConn.Open() 
         Using dbRdr As SqlDataReader = dbCmd.ExecuteReader(CommandBehavior.SingleRow) 
          dbRdr.Read() 
          If dbRdr.HasRows Then 
           filePath = dbRdr("Path") 
           trxContext = dbRdr("TrxContext") 
          End If 
          dbRdr.Close() 

          Using dest As New SqlFileStream(filePath, trxContext, FileAccess.Write) 
           dest.Write(fileBytes, 0, fileBytes.Length) 
           dest.Close() 
          End Using 
         End Using 
        End Using 
        dbConn.Close() 
       End Using 
       trxScope.Complete() 
      End Using 
     Catch ex As Exception 
      Elmah.ErrorSignal.FromCurrentContext().Raise(ex) 
     End Try 
Смежные вопросы