locked
Multiple File Download simultaneously RRS feed

  • Question

  • I have a class that uses a BackGroundWorker to download a single file using HttpWebRequest and HttpWebResponse

    Downloading single file works.

    But if I make two objects of that class and start downloading 2 different files simultaneously, there is nothing produced. Execution exits after getResponse() without any error or exception.

    Is there any way to achieve simultaneous file download?

    Monday, May 23, 2011 6:33 PM

Answers

  • Put a button and 2 long textboxes on Form1 of a new Windows Forms Application.
    Replace the Form1 code with:

    Imports System.Net
    Imports System.ComponentModel
    Public Class Form1
      
    Dim WCs As New List(Of WebClient)
      
    Private Sub Button1_Click(ByVal sender As Object, _
                                
    ByVal e As EventArgs) Handles Button1.Click
        WCs.Add(
    New WebClient)
        WCs.Add(
    New WebClient)
        
    AddHandler WCs(0).DownloadFileCompleted, AddressOf WC_DownloadFileComplete
        
    AddHandler WCs(1).DownloadFileCompleted, AddressOf WC_DownloadFileComplete
        
    AddHandler WCs(0).DownloadProgressChanged, AddressOf WC_ProgressChanged
        
    AddHandler WCs(1).DownloadProgressChanged, AddressOf WC_ProgressChanged
        WCs(0).DownloadFileAsync(
    New Uri("http://www.fileden.com/files/2010/2/15/2761729/Cppup/Setup.rar"), "r1.rar")
        WCs(1).DownloadFileAsync(
    New Uri("http://www.fileden.com/files/2010/2/15/2761729/SoftwaresZoo/SZTUT.rar"), "r2.rar")
      
    End Sub
      Sub WC_ProgressChanged(ByVal sender As ObjectByVal e As DownloadProgressChangedEventArgs)
        
    Dim WC As WebClient = DirectCast(sender, WebClient)
        
    Dim Text As String = e.BytesReceived.ToString + " Bytes of " + e.TotalBytesToReceive.ToString + " downloaded of file "
        If WCs.IndexOf(WC) = 0 Then TextBox1.Text = Text + "r1.rar" Else TextBox2.Text = Text + "r2.rar"
      End Sub
      Sub WC_DownloadFileComplete(ByVal sender As ObjectByVal e As AsyncCompletedEventArgs)
        
    Dim WC As WebClient = DirectCast(sender, WebClient)
        
    Dim Text As String = " download completed"
        If WCs.IndexOf(WC) = 0 Then TextBox1.Text = "r1.rar" + Text Else TextBox2.Text = "r2.rar" + Text
        WCs.Remove(WC)
        WC.Dispose()
    End Sub
    End
     Class

    Tuesday, May 24, 2011 9:57 AM

All replies

  • Is there any way to achieve simultaneous file download?


    It's done all the time.  Something's wrong with your code.
    Monday, May 23, 2011 7:25 PM
  • Alright it worked for other URLs, but why it failed for these 2 URLs of same server:-

    http://www.fileden.com/files/2010/2/15/2761729/SoftwaresZoo/SZTUT.rar

    http://www.fileden.com/files/2010/2/15/2761729/Cppup/Setup.rar

    Can be downloaded successfully individually but not simultaneously, execution exits after -

    webResp = CType(webReq.GetResponse, HttpWebResponse)  'Without any exception

    Tuesday, May 24, 2011 6:03 AM
  • Alright it worked for other URLs, but why it failed for these 2 URLs of same server:-

    http://www.fileden.com/files/2010/2/15/2761729/SoftwaresZoo/SZTUT.rar

    http://www.fileden.com/files/2010/2/15/2761729/Cppup/Setup.rar

    Can be downloaded successfully individually but not simultaneously, execution exits after -

    webResp = CType(webReq.GetResponse, HttpWebResponse)  'Without any exception


    I have no problem downloading  both files simultaneously in IE9.
    Tuesday, May 24, 2011 6:12 AM
  • This is the code
    Imports System.ComponentModel
    Imports System.IO
    Imports System.Net
    Public Class DownloadFile
      Public Event OnError(ByVal s As Object, ByVal e As ErrorEventArgs)
      Public Event ProgressChanged(ByVal s As Object, ByVal e As EventArgs)
      Public Event DownloadCompleted(ByVal s As Object, ByVal e As EventArgs)
    #Region "Data Members"
      Private WithEvents bw As New BackgroundWorker
      Private trigger As New Threading.ManualResetEvent(True)
      Private _file As FileInfo, _PackageSize As Int32, _FileProgress As Long, _currentSpeed As Long, _stopWatchCycles As Int32, _busy As Boolean, _paused As Boolean, _lastSize As Long
    #End Region
      Public Class ErrorEventArgs : Inherits System.EventArgs
        Public exception As Exception
        Public Sub New(ByVal ex As String)
          exception = New Exception(ex)
        End Sub
        Public Sub New(ByVal ex As Exception)
          exception = ex
        End Sub
      End Class
      Public Sub New()
        bw.WorkerReportsProgress = True
        bw.WorkerSupportsCancellation = True
        _PackageSize = 4096
        _stopWatchCycles = 50
        _paused = False
        _busy = False
      End Sub
      Public Class FileInfo
        Public Path As String
        Public Name As String
        Public URL As String
        Public ReadOnly Property FileLen() As Long
          Get
            Try
              Return My.Computer.FileSystem.GetFileInfo(Path).Length
            Catch ex As Exception
              Return CType(TotalLength, Long)
            End Try
    
          End Get
    
        End Property
        Public Directory As String
        Public TotalLength As String
        Public Sub New(ByVal path As String, ByVal _url As String)
          URL = _url
          Me.Path = path
          Me.Name = Me.Path.Split("\"c)(Me.Path.Split("\"c).Length - 1)
          Directory = Me.Path.Replace(Me.Name, "").Trim
          TotalLength = "0"
        End Sub
        Public Sub New(ByRef cdb As Database, ByVal row As Integer)
          URL = cdb.table(0)(1)(row)
          Me.Path = cdb.table(0)(0)(row)
          Me.Name = cdb.table(0)(0)(row).Split("\"c)(cdb.table(0)(0)(row).Split("\"c).Length - 1)
          Directory = Me.Path.Replace(Me.Name, "").Trim
          TotalLength = cdb.table(0)(2)(row)
    
        End Sub
    
      End Class
      Private Enum [Event]
        ProgressChanged = 0
        DownloadCompleted = 1
        ErrorOccured = 2
      End Enum
      Public Property File() As FileInfo
        Get
          Return _file
        End Get
        Set(ByVal value As FileInfo)
          _file = value
        End Set
      End Property
      Public Property PackageSize() As Int32
        Get
          Return _PackageSize
        End Get
        Set(ByVal value As Integer)
          If (value > 0) Then
            _PackageSize = value
          Else
            Throw New InvalidOperationException("Package Size must be > 0")
          End If
    
        End Set
      End Property
      Public Property StopWatchCyclesAmount() As Int32
        Get
          Return _stopWatchCycles
        End Get
        Set(ByVal value As Int32)
          If value > 0 Then
            _stopWatchCycles = value
          Else
            Throw New InvalidOperationException("The StopWatchCyclesAmount needs to be greather then 0")
          End If
        End Set
      End Property
      Public Property IsBusy() As Boolean
        Get
          Return _busy
        End Get
        Set(ByVal value As Boolean)
          If Me.IsBusy <> value Then
            _busy = value
            If Me.IsBusy Then
              bw.RunWorkerAsync()
    
            Else
              _paused = False
              bw.CancelAsync()
    
            End If
          End If
        End Set
      End Property
      Public ReadOnly Property Progress() As Integer
        Get
          Return ((_FileProgress + _lastSize) * 100) / File.TotalLength
        End Get
      End Property
      Public ReadOnly Property Speed() As Long
        Get
          Return _currentSpeed
        End Get
      End Property
      Public ReadOnly Property DownloadSpeed() As String
        Get
          Return FormatSizeBinary(Speed)
        End Get
      End Property
      Public Property IsPaused() As Boolean
        Get
          Return _paused
        End Get
        Set(ByVal value As Boolean)
          If Me.IsBusy Then
            If value <> Me.IsPaused Then
              _paused = value
              If Me.IsPaused Then
                trigger.Reset()
              Else
                trigger.Set()
              End If
    
            End If
          End If
        End Set
      End Property
      Public Sub Start()
        CalculateFSize()
        _FileProgress = 0
        bw.RunWorkerAsync()
    
      End Sub
      Public Sub Pause()
        IsPaused = True
      End Sub
      Public Sub [Resume]()
        IsPaused = False
      End Sub
      Public Shared Function FormatSizeBinary(ByVal size As Int64, Optional ByVal decimals As Int32 = 2) As String
        ' By De Dauw Jeroen - April 2009 - jeroen_dedauw@yahoo.com
        Dim sizes() As String = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}
        Dim formattedSize As Double = size
        Dim sizeIndex As Int32 = 0
        While formattedSize >= 1024 And sizeIndex < sizes.Length
          formattedSize /= 1024
          sizeIndex += 1
        End While
        Return Math.Round(formattedSize, decimals).ToString & sizes(sizeIndex)
      End Function
      Private Sub CalculateFSize()
        Try
          Dim webReq As HttpWebRequest = CType(Net.WebRequest.Create(File.URL), HttpWebRequest)
          Dim webResp As HttpWebResponse = CType(webReq.GetResponse, HttpWebResponse)
          File.TotalLength = webResp.ContentLength
        Catch ex As Exception
          RaiseEvent OnError(Me, New DownloadFile.ErrorEventArgs(ex))
        End Try
    
      End Sub
      Private Sub bw_work(ByVal s As Object, ByVal e As EventArgs) Handles bw.DoWork
        _busy = True
        If Not Directory.Exists(File.Directory) Then Directory.CreateDirectory(Me.File.Directory)
        Dim readBytes(Me.PackageSize - 1) As Byte
        Dim currentPackageSize As Int32
        Dim writer As New FileStream(File.Path, IO.FileMode.Append)
        Dim speedTimer As New Stopwatch
        Dim readings As Int32 = 0
        Dim webReq As HttpWebRequest
        Dim webResp As HttpWebResponse
        Dim size As Int64 = 0
        _lastSize = File.FileLen
        Try
          webReq = CType(Net.WebRequest.Create(Me.File.URL), HttpWebRequest)
          If (File.FileLen = 0) Then
            webResp = CType(webReq.GetResponse, HttpWebResponse)
            size = webResp.ContentLength
            File.TotalLength = size.ToString
          ElseIf File.FileLen = CType(File.TotalLength, Double) Then
            writer.Close()
            fireEventFromBgw([Event].ProgressChanged)
            _busy = False
            Exit Sub
          Else
            webReq.AddRange(CType(File.FileLen, Integer))
            webResp = CType(webReq.GetResponse, HttpWebResponse)
            size = webResp.ContentLength
          End If
        Catch ex As Exception
          Dim ec As New ErrorEventArgs(ex)
          writer.Close()
          _busy = False
          fireEventFromBgw([Event].ErrorOccured, ec)
          Exit Sub
        End Try
    
        While _FileProgress < size
          If bw.CancellationPending Then
            speedTimer.Stop()
            writer.Close()
            webResp.Close()
            _busy = False
            fireEventFromBgw([Event].ErrorOccured, New ErrorEventArgs("Download Worker Stopped due to external commands"))
            Exit Sub
          End If
          trigger.WaitOne()
          speedTimer.Start()
          Try
            currentPackageSize = webResp.GetResponseStream().Read(readBytes, 0, Me.PackageSize)
          Catch ex As Exception
            Dim ec As New ErrorEventArgs(ex)
            writer.Close()
            fireEventFromBgw([Event].ErrorOccured, ec)
            Exit Sub
          End Try
    
          _FileProgress += currentPackageSize
    
          fireEventFromBgw([Event].ProgressChanged)
          writer.Write(readBytes, 0, currentPackageSize)
          readings += 1
          If readings >= Me.StopWatchCyclesAmount Then
            _currentSpeed = CInt(Me.PackageSize * StopWatchCyclesAmount * 1000 / (speedTimer.ElapsedMilliseconds + 1))
            speedTimer.Reset()
            readings = 0
          End If
        End While
        fireEventFromBgw([Event].DownloadCompleted)
        speedTimer.Stop()
        writer.Close()
        webResp.Close()
        _busy = False
        'fireEventFromBgw([Event].FileDownloadSucceeded)
    
      End Sub
      Private Sub fireEventFromBgw(ByVal eventName As [Event], Optional ByVal data As Object = Nothing)
        bw.ReportProgress(eventName, data)
      End Sub
      Private Sub bw_prg(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles bw.ProgressChanged
        Select Case e.ProgressPercentage
          Case [Event].ProgressChanged
            RaiseEvent ProgressChanged(Me, New EventArgs)
          Case [Event].DownloadCompleted
            RaiseEvent DownloadCompleted(Me, New EventArgs)
          Case [Event].ErrorOccured
            RaiseEvent OnError(sender, e.UserState)
        End Select
      End Sub
    End Class
    
    
    For Main Form --
    
    <pre lang="x-vbnet"> Private a1 As New DownloadFile, a2 As New DownloadFile
    
    Private Sub asd() Handles Me.Load
      a1.File = New DownloadFile.FileInfo(CurDir() + "\r1.rar", "http://www.fileden.com/files/2010/2/15/2761729/Cppup/Setup.rar")
        a1.Start()
        a2.File = New DownloadFile.FileInfo(CurDir() + "\r2.rar", "http://www.fileden.com/files/2010/2/15/2761729/SoftwaresZoo/SZTUT.rar")
        a2.Start()
      End Sub
    
    Where's the problem!
    Tuesday, May 24, 2011 6:31 AM
  • Put a button and 2 long textboxes on Form1 of a new Windows Forms Application.
    Replace the Form1 code with:

    Imports System.Net
    Imports System.ComponentModel
    Public Class Form1
      
    Dim WCs As New List(Of WebClient)
      
    Private Sub Button1_Click(ByVal sender As Object, _
                                
    ByVal e As EventArgs) Handles Button1.Click
        WCs.Add(
    New WebClient)
        WCs.Add(
    New WebClient)
        
    AddHandler WCs(0).DownloadFileCompleted, AddressOf WC_DownloadFileComplete
        
    AddHandler WCs(1).DownloadFileCompleted, AddressOf WC_DownloadFileComplete
        
    AddHandler WCs(0).DownloadProgressChanged, AddressOf WC_ProgressChanged
        
    AddHandler WCs(1).DownloadProgressChanged, AddressOf WC_ProgressChanged
        WCs(0).DownloadFileAsync(
    New Uri("http://www.fileden.com/files/2010/2/15/2761729/Cppup/Setup.rar"), "r1.rar")
        WCs(1).DownloadFileAsync(
    New Uri("http://www.fileden.com/files/2010/2/15/2761729/SoftwaresZoo/SZTUT.rar"), "r2.rar")
      
    End Sub
      Sub WC_ProgressChanged(ByVal sender As ObjectByVal e As DownloadProgressChangedEventArgs)
        
    Dim WC As WebClient = DirectCast(sender, WebClient)
        
    Dim Text As String = e.BytesReceived.ToString + " Bytes of " + e.TotalBytesToReceive.ToString + " downloaded of file "
        If WCs.IndexOf(WC) = 0 Then TextBox1.Text = Text + "r1.rar" Else TextBox2.Text = Text + "r2.rar"
      End Sub
      Sub WC_DownloadFileComplete(ByVal sender As ObjectByVal e As AsyncCompletedEventArgs)
        
    Dim WC As WebClient = DirectCast(sender, WebClient)
        
    Dim Text As String = " download completed"
        If WCs.IndexOf(WC) = 0 Then TextBox1.Text = "r1.rar" + Text Else TextBox2.Text = "r2.rar" + Text
        WCs.Remove(WC)
        WC.Dispose()
    End Sub
    End
     Class

    Tuesday, May 24, 2011 9:57 AM
  • Hi AksHay,

    Welcome to the MSDN Forum.

    In actrually, it isn't no error, the exception has been handled in the  CalculateFSize and bw_work subroutine. So you should step into these two subroutine to see what happened.

    In addition, if it is possible, you can take John's ways.

    Best regards,


    Mike Feng [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, May 25, 2011 10:35 AM
    Moderator