DownloadFileAsync is downloading incomplete file - vb.net

Partcode
Targeted .net core is 4.0, using "visual studio 2017"
Sub DownloadFile()
Dim wc As New WebClient
Try
Dim durl As String = "https://onedrive.live.com/download?cid=9B804CF9A004FFF3&resid=9B804CF9A004FFF3%212166&authkey=ABv40n0yI5bLOAo"""
'wc.Headers.Add("user-agent", "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.2.12) Gecko/20101026 Firefox/3.6.12 (.NET CLR 3.5.30729)")
'wc.DownloadFile(durl, Application.StartupPath & "\Temp.rar")
wc.DownloadFileAsync(New Uri(durl), "test.rar")
Catch ex As Exception
SendToLogFile("Download " & ex.Message)
End Try
End Sub
Problem:
with wc.Headers.Add method downloaded file size was 78 kb, without headers download file size is 28 Kb. actual file size is 110kb or more . I tried in another pc assuming network/firewall issue but the result is same and incomplete.
What I Tried :
I tried the downloadfileasync method, the downloadfile method, and the My.Computer.Network.DownloadFile method, but they all resulted in a partial download. When I paste the url into Chrome or another browser, it works perfectly.
I need this code to work on all Windows operating system versions

To do that you can use several techniques.
Here a pair of those:
Try
'Using HttpClient
Using wc As HttpClient = New HttpClient()
Dim bytes() As Byte = wc.GetByteArrayAsync("https://onedrive.live.com/download?cid=9B804CF9A004FFF3&resid=9B804CF9A004FFF3%212166&authkey=ABv40n0yI5bLOAo").Result
Using sw As New MemoryStream(bytes)
Using sr As Stream = File.Create("test.rar")
sw.CopyTo(sr)
End Using
End Using
End Using
'Using WebClient
Using wc As WebClient = New WebClient()
Dim bytes() As Byte = wc.DownloadData("https://onedrive.live.com/download?cid=9B804CF9A004FFF3&resid=9B804CF9A004FFF3%212166&authkey=ABv40n0yI5bLOAo")
Using sw As New MemoryStream(bytes)
Using sr As Stream = File.Create("test1.rar")
sw.CopyTo(sr)
End Using
End Using
End Using
Catch ex As Exception
Debug.WriteLine(ex.ToString)
End Try

Related

VB.net httpclient receives Header OK 200, but content is empty

I use MS Visual Studio 2017 in Windows 10 and tried following httpclient by VB.net in order to get html of, for example, yahoo.com. I could get Header OK status 200 while its contents consists of several funny letters and finally resulsted in empty when converting to string.
Would you please advise how to receive contents by means of httpclient?
I tried variety sets of header which are not a cause of the problem. I assume the cause exists in how to convert the contents or I may need to access again the site after receiving a header in order to receive the content???.
Dim url As String = "https://yahoo.com"
Dim httpclienthandler0 = New HttpClientHandler()
httpclienthandler0.UseCookies = True
httpclienthandler0.SslProtocols = SecurityProtocolType.Tls Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12 Or SecurityProtocolType.Tls13
httpclienthandler0.ServerCertificateCustomValidationCallback = AddressOf OnRemoteCertificateValidationCallback
Dim httpclient0 As New HttpClient(httpclienthandler0)
httpclient0.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
httpclient0.DefaultRequestHeaders.Add("Accept-Encoding", "gzip, deflate, br")
httpclient0.DefaultRequestHeaders.Add("Accept-Language", "en-us;q=0.7,en;q=0.3")
httpclient0.DefaultRequestHeaders.Add("Cache-Control", "max-age=0")
httpclient0.DefaultRequestHeaders.Add("Connection", "keep-alive")
httpclient0.DefaultRequestHeaders.Add("Upgrade-Insecure-Requests", "1")
httpclient0.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.82 Safari/537.36")
httpclient0.Timeout = TimeSpan.FromSeconds(10.0)
Try
Dim res As HttpResponseMessage = Await httpclient0.GetAsync(New Uri(url))
res.EnsureSuccessStatusCode()
Dim responseBody As String = Await res.Content.ReadAsStringAsync()
Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding("utf-8")
Dim html As String = String.Empty
Using stream = Await res.Content.ReadAsStreamAsync()
Using reader = DirectCast(New IO.StreamReader(stream, enc, True), IO.TextReader)
html = Await reader.ReadToEndAsync()
End Using
End Using
Catch ex As HttpRequestException
Dim ex1 As Exception = ex
While (ex1 IsNot Nothing)
Console.WriteLine("Ex Message: {0} ", ex1.Message)
ex1 = ex1.InnerException
End While
Catch ex As TaskCanceledException
Dim ex2 As Exception = ex
Console.WriteLine(vbCr + "Timeout!)
Console.WriteLine("Ex MEssage: {0} ", ex2.Message)
End Try
Following codes derived from above are specific code that gets empty contents.
Dim responseBody As String = Await res.Content.ReadAsStringAsync()
and I tried next code instead of responseBody.
Using stream = Await res.Content.ReadAsStreamAsync()
Using reader = DirectCast(New IO.StreamReader(stream, enc, True), IO.TextReader)
html = Await reader.ReadToEndAsync()
End Using
End Using
However both code resulted in empty.
Thank you indeed for your time to read and answer.

VB.Net Web Scraper - The request was aborted: Could not create SSL/TLS secure channel

I am working on a web scraping program and I am getting the following error on sites that have Tls 1.0 and 1.1 disabled, and Tls 1.2 and 1.3 enabled:
'The request was aborted: Could not create SSL/TLS secure channel'
I should also note that I am using .Net version 4.8
This is the site that I am using to check:
https://www.cdn77.com/tls-test
I've read nearly a dozen posts on the topic and none of the solutions have worked for me.
This is the code. It works on most sites:
Try
ServicePointManager.Expect100Continue = True
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 Or
SecurityProtocolType.Tls13
Dim address = New Uri(url)
Using client = New WebClient()
Dim stream = client.OpenRead(address) ' This is where exception is caught
Using sr = New StreamReader(stream)
Dim page = sr.ReadToEnd()
Return page
End Using
End Using
Catch ex As Exception
Return ex.Message
End Try
I think you will not find so much sites with only TLS1.3
I use this function for many years:
Function getFromURL(ByVal url As String) As String
Dim request As System.Net.WebRequest = System.Net.WebRequest.Create(url)
'request.Headers.Add("HTTP_USER_AGENT", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.40607; .NET CLR 1.1.4322; .NET CLR 2.0.50215)")
System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12
Dim response As System.Net.WebResponse
response = request.GetResponse()
Dim responseStream As System.IO.Stream = response.GetResponseStream()
Dim reader As System.IO.StreamReader = New System.IO.StreamReader(responseStream)
Return reader.ReadToEnd()
End Function

SqlFileStream writing in separate thread not working

Learning and testing using Sql FILESTREAM for a web app. A client uploads a large file form the web page which takes 'X' time and when fully uploaded shows 100% complete. However, very large files also take time for SqlFileStream to write to the file system so I want to spin off a thread to complete that part. The code I've got seems to work fine but no data ends up in the filestream file.
I'm wrapping the initial record creation in it's own transaction scope and using a separate transaction scope in the thread. In the threaded routine I have the appropriate PathName() and TransactionContext but I assume I'm missing something while using a thread.
I've commented out the normal SqlFileStream call which works fine. Can you see anything wrong with what I'm doing here?
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
Obviously this is a complex issue. I actually got it to work with the code below. However I eventually abandoned using SQL FILESTREAM altogether due to too much complexity in getting it all set up.
This is an existing web application with the sql server on a different box. After I got the filestreaming to work the next hurdle was authentication setup. Filestream requires Integrated Security on your connection string. Even with windows authentication on our Intranet app, I could not get the web app to use the windows credentials when connecting to the database. It always seemed to use the computer name or the app pool service. I tried many many examples I found on the net and here to no avail. Even if I got that to work then I would want to use and Active Directory group over individual logins which looked to be another hurdle.
This app stores documents in a varbinary column so that full text search can be enabled at some point. The issue was with large files which are generally pictures or videos. Since you can't search text on those anyway the strategy now is to store those on the file system and all other searchable docs (.docx, .pptx, etc) will still be stored in the varbinary. I'm actually sad that I could not get filestream to work as it seems like the ideal solution. I'll come back to it some day but it really should not be so frickin complicated. :-(
The code I got working is:
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
With the task procedure of:
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

ShowBalloonTip not working in Windows 1 when it worked it previous editions of WIndows

Ever since I upgraded to Windows 10, my program refuses to show a notify icon for when an update is released, it worked when I used Windows 7.
This is the code:
Imports System.Net
Public Class Updates
Public Sub CheckForUpdates()
Try
Dim request As System.Net.HttpWebRequest = CType(System.Net.HttpWebRequest.Create("http://versionfile.txt"), HttpWebRequest)
Dim response As System.Net.HttpWebResponse = CType(request.GetResponse(), HttpWebResponse)
Dim sr As System.IO.StreamReader = New System.IO.StreamReader(response.GetResponseStream())
Dim newestversion As String = sr.ReadToEnd()
Dim currentversion As String = Application.ProductVersion
If newestversion > currentversion Then
CardMaker.NotifyIcon1.ShowBalloonTip(3000, "Update Available!", "Click Here to download it", ToolTipIcon.Info)
End If
Catch ex As Exception
MsgBox("An error occured while trying to check for updates:" + vbNewLine + ex.Message + vbNewLine + vbNewLine + ex.ToString, Title:="Error 006")
My.Computer.Clipboard.SetText(ex.ToString)
End Try
End Sub
End Class
Now this code makes sense, and it works theoretically, but not practically, on windows 10 that is. Problem is, that the program is out there and people may not actually be receiving the notification either if they are using Windows 10.
Is this a known issue? If so, is there a work around to this?
Neve rmind, fixed it. You have to select the notification icon in the visual designer for the balloon tip to show up, although it was defined in the code.

Writing FileStream to Local Path and not the server

I have the following code working successfully:
Protected Sub ExportExcel_Click(sender As Object, e As EventArgs) Handles ExportExcel.Click
Dim warnings As Warning()
Dim streamids As String()
Dim mimeType As String
Dim encoding As String
Dim filenameExtension As String
Dim fileName As String = "D:\Report" & DateTime.Now.ToString("yyyyMMdd_HHmmss") & ".xls"
Dim bytes As Byte() = ReportViewer1.LocalReport.Render("Excel", Nothing, mimeType, encoding, filenameExtension, streamids, warnings)
Using fs As New FileStream(fileName, FileMode.Create)
fs.Write(bytes, 0, bytes.Length)
End Using
lblMessage.Text = Functions.GetMessageConfirm("Report downloaded successfully in your D:/ at: " & Now.ToString)
End Sub
This code saves the file in the web server. I want to save the file on the client machine.
You're halfway there, probably. You can't just save files on the client anyway. Clients are webbrowsers, and they run JavaScript.
What you can do is use the download functionality of webbrowsers, to let them download the file which you just created. To do so, put the output on the server in a directory from where it can be downloaded, then return the new URL to the client.