2016-02-12 55 views
0

使用Sql FILESTREAM學習和測試Web應用程序。客戶端上傳一個大型文件形式的網頁,需要'X'時間,當完全上傳顯示100%完成。但是,非常大的文件也需要時間讓SqlFileStream寫入文件系統,所以我想剝離一個線程來完成該部分。我得到的代碼似乎工作正常,但沒有數據在文件流文件中結束。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,因爲所有設置都太複雜了。

這是一個現有的Web應用程序與SQL Server在不同的盒子上。在獲得文件流後,下一個障礙是身份驗證設置。 Filestream需要您的連接字符串的集成安全性。即使在我們的Intranet應用程序上使用Windows身份驗證,我也無法讓Web應用程序在連接到數據庫時使用Windows憑據。它似乎總是使用計算機名稱或應用程序池服務。我嘗試了許多我在網上找到的例子,在這裏無濟於事。即使我得到這個工作,然後我想要使用和Active Directory組在單個登錄看起來是另一個障礙。

此應用將文檔存儲在varbinary列中,以便可以在某個時間啓用全文搜索。問題在於大型文件,通常是圖片或視頻。由於無法搜索文本,所以現在的策略是將這些文件存儲在文件系統中,並且所有其他可搜索的文檔(.docx,.pptx等)仍將存儲在varbinary中。我真的很傷心,因爲它看起來是理想的解決方案,所以我無法使文件流工作。有一天我會回來的,但它真的不應該這麼複雜。 :-(

的代碼我得到的工作是:

    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 
相關問題