DownloadFileAsync via Command line

B

Bedwell

Ok, I’m using the method DownloadFileAsync to download a large file and I
also use the DownloadProgressChanged event to show users how far along they
are in downloading the file. I put this into a WinForms application, make a
call to the download file method (behind a button click event) and the
download works fine. If I call the download file method from Commandline
switch in the WinForms app it fails, it starts to download the file but never
finishes. Any idea why running a WinForms from a commandline would cause this
function not to work?


Example: Call GetFile from Button click, it works. Call GetFile from
commandline switch passed into the same app, it doesn’t download. Note: The
file being downloaded is large.

Public Function GetFile() As Boolean

Try

Dim client As New WebClient
Dim fld As DirectoryInfo
Dim fil As FileInfo = New FileInfo("C:\LocalFileName.exe")

fld = fil.Directory
client.Credentials = CredentialCache.DefaultCredentials

If fld.Exists = False Then
Dim Msg As String = "Destination folder for setup file does
not exist."
Throw New Exception(Msg)
End If

AddHandler client.DownloadProgressChanged, AddressOf
DownloadProgressCallback
Dim uri As Uri = New
Uri("http://www.SomeSite.com/downloads/ServerFileName.exe") ' This file is
large (100 Megabtyes)
client.DownloadFileAsync(uri, fil.FullName)

Catch Err As Exception
WriteMessage(Err.Message & vbTab & Err.StackTrace)
End Try
End Function

Public Sub DownloadProgressCallback(ByVal sender As Object, ByVal e As
DownloadProgressChangedEventArgs)
WriteMessage("DownloadProgressCallback")
End Sub
 
L

Leon Mayne

Bedwell said:
Ok, I’m using the method DownloadFileAsync to download a large file and I
also use the DownloadProgressChanged event to show users how far along
they
are in downloading the file. I put this into a WinForms application, make
a
call to the download file method (behind a button click event) and the
download works fine. If I call the download file method from Commandline
switch in the WinForms app it fails, it starts to download the file but
never
finishes. Any idea why running a WinForms from a commandline would cause
this
function not to work?


Example: Call GetFile from Button click, it works. Call GetFile from
commandline switch passed into the same app, it doesn’t download. Note:
The
file being downloaded is large.

Public Function GetFile() As Boolean

Try

Dim client As New WebClient
Dim fld As DirectoryInfo
Dim fil As FileInfo = New FileInfo("C:\LocalFileName.exe")

fld = fil.Directory
client.Credentials = CredentialCache.DefaultCredentials

If fld.Exists = False Then
Dim Msg As String = "Destination folder for setup file does
not exist."
Throw New Exception(Msg)
End If

AddHandler client.DownloadProgressChanged, AddressOf
DownloadProgressCallback
Dim uri As Uri = New
Uri("http://www.SomeSite.com/downloads/ServerFileName.exe") ' This file is
large (100 Megabtyes)
client.DownloadFileAsync(uri, fil.FullName)

Catch Err As Exception
WriteMessage(Err.Message & vbTab & Err.StackTrace)
End Try
End Function

Public Sub DownloadProgressCallback(ByVal sender As Object, ByVal e As
DownloadProgressChangedEventArgs)
WriteMessage("DownloadProgressCallback")
End Sub

Could you post the code block you are trying to use for loading in the file
from the command line?
 
B

Bedwell

Here is my main mod code for my test app:

Module Module1

Public Sub Main()

If Microsoft.VisualBasic.Command.Length > 0 Then
Dim o As New Class1
o.GetFile()
Else
Dim f As New Form1
f.ShowDialog()
End If

End Sub

End Module

And Here is the form Code:
Public Class Form1

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click

Dim o As New Class1
o.GetFile()


End Sub
End Class
 
L

Leon Mayne

Bedwell said:
Here is my main mod code for my test app:

Module Module1

Public Sub Main()

If Microsoft.VisualBasic.Command.Length > 0 Then
Dim o As New Class1
o.GetFile()
Else
Dim f As New Form1
f.ShowDialog()
End If

End Sub

End Module

Change the Main signature to:
Sub Main(ByVal ParamArray args() As String)
and access the command line parameters using args, e.g. the first parameter
would be args(0):
Console.WriteLine(args(0))
Check if parameters have been enetered using args.Length.

I can't work out what you're doing after this though, shouldn't it be
something like:

Module Module1
Sub Main(ByVal ParamArray args() As String)
If args.Length > 0 Then
Dim o As New Class1
o.GetFile(args(0))
Else
Dim f As New Form1
f.ShowDialog()
End If
End Sub
End Module

Public Class Form1
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim o As New Class1
o.GetFile(TextBox1.Text)
End Sub
End Class

Public Function GetFile(ByVal pFileName as String) As Boolean
Try
<snip>
Dim fil As FileInfo = New FileInfo(pFileName)
End Try
End Function

And you have a textbox on Form1 which asks for a file?
 
L

Leon Mayne

Bedwell said:
This just a sample app I put together to show the problem I ran into, so
some
things are hard coded, like file path. But the problem is reproducible
with
this code.

The Source for my test app is here:
http://www.classicresystems.com/downloads/DownLoadExample.zip

OK, I think I know the problem. It's the same issue I had when I coding a
similar command line app that needed to stay loaded while listening for
events.

What's happening is that when you run the windows forms version the form
keeps the application loaded in memory, and so the handler can receive the
events correctly. When you run the command line version (without calling the
form), the application will run through and start off the asynchronous file
download, but then the app will finish and close (as there is nothing
keeping it open).

I'm not sure what the best option for this is. You could either:

1) Add a Console.ReadLine() statement at the bottom of your sub main:

Module Module1
Public Sub Main(ByVal ParamArray args() As String)
If args.Length > 0 Then
Dim o As New Class1
o.GetFile()
Else
Dim f As New Form1
f.ShowDialog()
End If
Console.ReadLine()
End Sub
End Module

Which will keep it alive until the user hits return, or

2) Add some kind of loop which will check a global variable that gets set
when the file has downloaded (set in your async. function):

Module Module1

Private _blnDownloadFinished As Boolean

Public Property DownloadFinished() As Boolean
Get
Return _blnDownloadFinished
End Get
Set(ByVal value As Boolean)
_blnDownloadFinished = value
End Set
End Property

Public Sub Main(ByVal ParamArray args() As String)

If args.Length > 0 Then
Dim o As New Class1
o.GetFile()
Else
Dim f As New Form1
f.ShowDialog()
End If

While _blnDownloadFinished = False
Threading.Thread.Sleep(5000)
End While

End Sub

End Module

Class1.vb:
Public Sub DownloadCompleteCallback(ByVal sender As Object, ByVal e As
AsyncCompletedEventArgs)
WriteMessage("DownloadCompleteCallback")
Module1.DownloadFinished = True
End Sub

This example is a bit dirty and doesn't check to make sure the file download
is going OK, etc, so you'll have to play with it a bit.
 
B

bedwell

Thank you Leon, the light went off when I read your post. Async operation
alone will not keep the app open. I appreciate your help!
 
Top