none
system.stream.io.Write() hung: RRS feed

  • Question

  • I have a loop that contains a system.stream.io.Write()

    The write function gets hung. I am trying to come up with logic to abort or back out of the thread that's calling the Stream Write method. Can you point to the right logic exit or abort the thread that's call the write. I have gave you a sample code snippet.

    clsStream = clsRequest.GetRequestStream() clsStream.WriteTimeout = 5000 For offset As UInteger = 0 To File.Length Step

    'The code gets hung on the line below. I am trying to backout of thread after

    a 'certain amount of seconds

    clsStream.Write(File, offset, chunkSize) Application.DoEvents() Me.Refresh() Next



    pianoboyCoder

    Thursday, June 22, 2017 5:59 PM

All replies

  • I have a loop that contains a system.stream.io.Write()

    The write function gets hung. I am trying to come up with logic to abort or back out of the thread that's calling the Stream Write method. Can you point to the right logic exit or abort the thread that's call the write. I have gave you a sample code snippet.

    clsStream = clsRequest.GetRequestStream() clsStream.WriteTimeout = 5000 For offset As UInteger = 0 To File.Length Step

    'The code gets hung on the line below. I am trying to backout of thread after

    a 'certain amount of seconds

    clsStream.Write(File, offset, chunkSize) Application.DoEvents() Me.Refresh() Next



    pianoboyCoder

    Is that an HTTPWebResponse that you're using?

    If so, you don't have it set up correctly. I posted this a few weeks ago:

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/77157b77-6ec6-4be1-bda0-e3f6b4ba118f/download-file-webbrowser-control-or-httpwebrequest?forum=vbgeneral

    You might also consider using a WebClient.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Thursday, June 22, 2017 6:08 PM
  • Its a FTP Request or FTP Response

       myfilename = Path.GetFileName(TB_filename.Text)
                clsRequest = DirectCast(System.Net.WebRequest.Create("ftp://" & TB_ipaddress.Text & "/" & myfilename), System.Net.FtpWebRequest)
    
                Dim Date1 As DateTime
                Dim Date2 As DateTime
    
                clsRequest.Credentials = New System.Net.NetworkCredential(TB_username.Text, TB_password.Text)
    
                clsRequest.Method = System.Net.WebRequestMethods.Ftp.UploadFile
                clsRequest.KeepAlive = True
                clsRequest.ConnectionGroupName = "MyGroupName"
                clsRequest.ServicePoint.ConnectionLimit = 2
                clsRequest.UseBinary = True


    pianoboyCoder


    Thursday, June 22, 2017 6:47 PM
  • Its a FTP Request or FTP Response

       myfilename = Path.GetFileName(TB_filename.Text)
                clsRequest = DirectCast(System.Net.WebRequest.Create("ftp://" & TB_ipaddress.Text & "/" & myfilename), System.Net.FtpWebRequest)
    
                Dim Date1 As DateTime
                Dim Date2 As DateTime
    
                clsRequest.Credentials = New System.Net.NetworkCredential(TB_username.Text, TB_password.Text)
    
                clsRequest.Method = System.Net.WebRequestMethods.Ftp.UploadFile
                clsRequest.KeepAlive = True
                clsRequest.ConnectionGroupName = "MyGroupName"
                clsRequest.ServicePoint.ConnectionLimit = 2
                clsRequest.UseBinary = True


    pianoboyCoder


    If it's a big file, a WebClient will disappoint you but if you use the following:

    ftpRequest.Method = WebRequestMethods.Ftp.UploadFile

    Then you have the ability to cancel it midway:

    ftpRequest.Method = WebRequestMethods.Ftp.UploadFile
    ftpRequest.Abort()


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Thursday, June 22, 2017 8:11 PM
  • im a little confused one what are you are saying to do.. Are you saying use this logic below:

    If it's a big file, a WebClient will disappoint you but if you use the following:

    ftpRequest.Method = WebRequestMethods.Ftp.UploadFile

    Then you have the ability to cancel it midway:

    ftpRequest.Method = WebRequestMethods.Ftp.UploadFile
    ftpRequest.Abort()

    Then remove this logic below from code:

        clsRequest.Credentials = New System.Net.NetworkCredential(TB_username.Text, TB_password.Text)

                clsRequest
    .Method = System.Net.WebRequestMethods.Ftp.UploadFile
                clsRequest
    .KeepAlive = True
                clsRequest
    .ConnectionGroupName = "MyGroupName"
                clsRequest
    .ServicePoint.ConnectionLimit = 2
                clsRequest
    .UseBinary = True


    pianoboyCoder

    Thursday, June 22, 2017 8:55 PM
  • im a little confused one what are you are saying to do.. Are you saying use this logic below:

    If it's a big file, a WebClient will disappoint you but if you use the following:

    ftpRequest.Method = WebRequestMethods.Ftp.UploadFile

    Then you have the ability to cancel it midway:

    ftpRequest.Method = WebRequestMethods.Ftp.UploadFile
    ftpRequest.Abort()

    Then remove this logic below from code:

        clsRequest.Credentials = New System.Net.NetworkCredential(TB_username.Text, TB_password.Text)

                clsRequest
    .Method = System.Net.WebRequestMethods.Ftp.UploadFile
                clsRequest
    .KeepAlive = True
                clsRequest
    .ConnectionGroupName = "MyGroupName"
                clsRequest
    .ServicePoint.ConnectionLimit = 2
                clsRequest
    .UseBinary = True


    pianoboyCoder

    Sorry for the confusion:

    A WebClient will work but on a large file, cancelling it midway isn't supported.

    Using an FTPWebRequest allows you to abort the operation whenever you want so the file size isn't an issue at all.

    Make sense?


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Thursday, June 22, 2017 9:04 PM
  • This proved to be more involved than I thought, but let me know if you're interested and I'll continue over the weekend with it:

    My goal was to upload using an FTPWebRequest and allow the upload to be cancelled at any point in time (safely - without throwing an exception).

    Also, I want it to report progress like you see above.

    Lastly, since it's FTP, I want it to "resume" partial uploads. A WebClient can't do that (it doesn't deal with streams at all) but with this, it can.

    It's not "ready to show" just yet but if you're interested, let me know and I'll continue with it until it is.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Friday, June 23, 2017 8:26 PM
  • The forum is acting weird again so I thought I'd post this in case it decided to stop sending e-mails again.

    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Friday, June 23, 2017 9:07 PM
  • Yes I am interested. If possible you can upload project so I can follow what you are doing.

    pianoboyCoder

    Saturday, June 24, 2017 8:54 PM
  • Yes I am interested. If possible you can upload project so I can follow what you are doing.

    pianoboyCoder

    Ok

    I'll be back on this tomorrow sometime then. I stopped with it but I know where I was.

    I'll explain what it's doing once you're able to look at the code.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Saturday, June 24, 2017 8:56 PM
  • Yes I am interested. If possible you can upload project so I can follow what you are doing.

    pianoboyCoder


    Coder,

    I have the project directory zipped up and uploaded to my FTP site here:

    https://fls.exavault.com/share/view/i57a-2gtpfat3

    Download that somewhere and extract it, then open the solution in your version of Visual Studio. When you do, you’ll be prompted to update it to your version because I use an older version. Just follow the prompts and it should all work ok.

    When it opens in Visual Studio, look in Solution Explorer and you’ll see that there are two projects in it:

    The project named “Uploader” is a class library that does the work of the uploading, so you might want to take a few minutes and peruse through the code. When it’s built, a .dll file is created and that’s then referenced in the test form (Form1.vb).

    You’ll see my settings for server name, user name, and password. Feel free to use it if you want but there are some things with it that I don’t like (it’s a new web host that I’m using) as I’ll explain here shortly.

    I took a bunch of photos and zipped them up so that I could use for my test. You’ll see that file path shown so obviously you’ll want to modify that on your end.

    I’ll point out the obvious: This is just a test form – not a suggested layout or anything like that at all; it’s just so that I’d have something to test the assembly with.

    I’ll start the upload:

    After a minute has elapsed, it will then show an approximation of the remaining time:

    Now I’ll cancel it:

    When you do that, the “OperationComplete” event is raised and if you’ll hover your mouse over the ‘e’, you’ll see the following:

    At this point I was going to show you how it resumes but – I can’t. Apparently my new web host has decided to save themselves some money: If the upload is incomplete the incomplete file is deleted!

    I’ll restart it and let it run to completion, then I’ll explain how it all works:

    I let it complete and this time – since I didn’t cancel it – the event args look like this:

    To confirm that it’s there, WS_FTP shows the following:

    *****

    Have a look at how I’ve set up the operation to run:

    uploader = New SingleFileUploader
    
    uploader.StartUpload(largeFilePath, _
        IO.Path.GetFileName(largeFilePath), _
        settings, "http://www.fls-online.net/VBNet_Forum/UploadDownload/")
    

    There are three mandatory parameters and one optional one:

     

    • The local file path (a string);
    • The name to give the remote file (a string);
    • An instance of another class in the library which has your FTP settings (FTP_Settings).

     

    Additionally, there’s an optional parameter: If your host has both an HTTP and an FTP server, if you give it the base HTTP url, it will then combine it with the remote file name and use that to get the size of the remote file (if applicable):

    Dim remoteFileSize As Nullable(Of Long) = Nothing If String.IsNullOrWhiteSpace(params.BaseHTTP_Url) Then Dim uri As New Uri(params.Settings.ServerName & params.RemoteFileName) remoteFileSize = Utilities.GetRemoteFileSize(uri, params.Settings.Credential) Else Dim base As String = params.BaseHTTP_Url If Not base.EndsWith("/"c) Then base &= "/"c End If remoteFileSize = Utilities.GetRemoteFileSize(base & params.RemoteFileName) End If


    HTTP will be a lot faster than FTP because FTP has to log in but the HTTP just looks at the file header and gets the size.

    All of the “work” is done inside a BackgroundWorker as you’ll see when you look at the code. The essence of it is this:

    It sets the parameters for the request (an FTPWebRequest) and then following that, a FileStream is created in a Using block. The FileStream’s content is the local file that you’re uploading.

    There’s a byte buffer that I have set up of exactly one meg. I want it large enough that it’s not impeding the upload speed but small enough that it’s able to detect a “cancel” fairly quickly. You might want to experiment with the value or maybe later I’ll make it a settable property so that you don’t have to rebuild it each time.

    From there, a stream is created from the request’s .GetRequestStream.

    Now a loop is started based on reading the FileStream’s buffer. Inside the loop, the stream is written to using the byte buffer and it continues until there are no bytes remaining – OR – until it detects that _userCancel has been set:

                            Using fs As FileStream = params.LocalFilePath.OpenRead
                                If remoteFileSize.HasValue AndAlso remoteFileSize > 0 Then
                                    fs.Position = remoteFileSize.Value
                                End If
    
                                stream = request.GetRequestStream
                                Dim len As Integer = fs.Read(fileBuffer, 0, bufferSize)
    
                                Do While len <> 0
                                    stream.Write(fileBuffer, 0, len)
                                    len = fs.Read(fileBuffer, 0, bufferSize)
    
                                    _uploadedSoFar = fs.Position
    
                                    If _operationSW IsNot Nothing AndAlso _operationSW.IsRunning Then
                                        If _operationSW.Elapsed.TotalSeconds > 0 Then
                                            If remoteFileSize.HasValue Then
                                                _uploadRate = (fs.Position - remoteFileSize.Value) / _operationSW.Elapsed.TotalSeconds
                                            Else
                                                _uploadRate = fs.Position / _operationSW.Elapsed.TotalSeconds
                                            End If
    
                                            If _operationSW.Elapsed.TotalMinutes > 1 AndAlso _uploadRate > 0 Then
                                                _approximateCompletionSeconds = ((_totalFileSize - _uploadedSoFar) / _uploadRate)
                                            End If
                                        End If
                                    End If
    
                                    If _userCancel Then
                                        request.Abort()
                                        Exit Do
                                    End If
                                Loop
    
                                stream.Close()
                            End Using


    The idea behind the resume – even though I have no way to test it – isn’t much different really:

    If the remote file exists, two things are changed: The method is changed from .UploadFile to .AppendFile. Also, the pointer (position) of the FileStream is advanced to where the new data is to start. Now it knows to take the new bytes and add them to the end of what’s currently there.

    It *should* work, but unfortunately I have no way to test it.

    When you look at the code, please note that the request and the stream are declared outside the Try/Catch. I do this because of the Finally clause that ensures those are closed/disposed no matter what.

    I hope you find this helpful. :)


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Sunday, June 25, 2017 11:20 AM