Excel vba download file with random file extension - asp.net

I am trying to write a code to automatically download files from a website by Excel vba. I know there are plenty of posts regarding this topic but no luck so far. The first few lines of code go like this:
Sub testing()
Dim ie as object
Url _base = "http://www..../download.aspx?id="
Num = cells(1,1).value
Set ie = createobject ("internetexplorer.application")
Ie.visible = true
For i = 1 to num
Url = url _base & i
....
Then I become clueless. The problem is that winhttp seems to only download csv files, and urldownloadtofile requires a solid url path ending with the file extension. However, my case is the link is redirecting to the actual file location (no extension shown), and also the file could be any extension such as pdf, jpg, and doc.
Thanks all in advance!

Ok, editing answer to fold in feedback, three different ways to make an HTTP request and it seems you are looking to trap a redirect which is status codes 300-303, 307-308. Try this and provide feedback as to whether or not you are redirected.
Option Explicit
Private Sub TestGetFileFromWeb()
Call SaveTextToFile(GetFileFromWeb2("http://www.wikipedia.com"), "c:\temp\wikipedia2.txt")
Call SaveTextToFile(GetFileFromWeb3("http://www.wikipedia.com"), "c:\temp\wikipedia3.txt")
'* placed last because it gives "Access Denied" Run-time error '-2147024891 &h80070005
'Call SaveTextToFile(GetFileFromWeb1("http://www.wikipedia.com"), "c:\temp\wikipedia1.txt")
Call SaveTextToFile(GetFileFromWeb1("http://www.bbc.com"), "c:\temp\bbc.txt")
End Sub
Private Function SaveTextToFile(ByRef sText As String, ByVal sFileName As String) As Boolean
'* Requires Tools ->References -> Microsoft Scripting Runtime
Dim fso As Scripting.FileSystemObject
Set fso = New Scripting.FileSystemObject
Dim txtOut As Scripting.TextStream
Set txtOut = fso.CreateTextFile(sFileName, , True)
txtOut.Write sText
txtOut.Close
Set txtOut = Nothing
Set fso = Nothing
SaveTextToFile = True
End Function
Private Function GetFileFromWeb1(ByVal sURL As String) As String
'* Requires Tools->References->Microsoft Xml, v.6.0
Dim xHTTPRequest As MSXML2.XMLHTTP60
Set xHTTPRequest = New MSXML2.XMLHTTP60
xHTTPRequest.Open "GET", sURL, False
xHTTPRequest.Send
Debug.Assert WasRedirected(xHTTPRequest.Status)
GetFileFromWeb1 = xHTTPRequest.ResponseText
End Function
Private Function GetFileFromWeb2(ByVal sURL As String) As String
'* Requires Tools->References->Microsoft WinHTTP Services, version 5.1
Dim oWinHttp As WinHttp.WinHttpRequest
Set oWinHttp = New WinHttp.WinHttpRequest
oWinHttp.Open "GET", sURL, False
oWinHttp.Send
Debug.Assert WasRedirected(oWinHttp.Status)
GetFileFromWeb2 = oWinHttp.ResponseText
End Function
Private Function WasRedirected(ByVal lStatus As Long) As Boolean
'http://qnimate.com/redirection-and-duplicate-content-in-websites/
'There are many types of HTTP redirection.
'
'300 Redirect or Multiple Choices
'301 Redirect or permanent redirect
'302 Redirect or Found or Temporary Redirect
'303 Redirect or See Other
'307 Redirect or Temporary Redirect
'308 Redirect or Permanent Redirect
'HTTP refresh header
WasRedirected = (lStatus = 300 Or lStatus = 301 Or lStatus = 302 Or lStatus = 303 Or lStatus = 307 Or lStatus = 308)
End Function
Private Function GetFileFromWeb3(ByVal sURL As String) As String
'* Requires Tools->References->Microsoft Xml, v.6.0
Dim xHTTPRequest As MSXML2.ServerXMLHTTP60
Set xHTTPRequest = New MSXML2.ServerXMLHTTP60
xHTTPRequest.Open "GET", sURL, False
xHTTPRequest.Send
Debug.Assert WasRedirected(xHTTPRequest.Status)
GetFileFromWeb3 = xHTTPRequest.ResponseText
End Function

Related

How to send multiple files with Response. ASP.NET

I'm trying to call below code in a loop hundreds of times:
Sub ExportReport(ByVal en As MyReport)
Dim warnings As Warning() = Nothing
Dim streamids As String() = Nothing
Dim mimeType As String = Nothing
Dim encoding As String = Nothing
Dim extension As String = Nothing
Dim bytes As Byte()
bytes = aReport.ServerReport.Render("WORD", Nothing, mimeType, encoding, extension, streamids, warnings)
Response.Buffer = True
Response.Clear()
Response.ContentType = mimeType
Response.AddHeader("content-disposition", "attachment; filename=" & en.ToString() & "." + extension)
Response.BinaryWrite(bytes)
Response.Flush()
Response.End()
End Sub
And I'm getting this error :
Server cannot append header after HTTP headers have been sent.
How can I change the code so that I can loop this piece of code? Thanks.
EDIT :
I added this line after Response.End()
Response.Redirect(Request.Url.AbsoluteUri)
And I get this error :
Cannot redirect after HTTP headers have been sent.
WWW works on a request / response mechanism. For every request there is only 1 response. You cannot change that basic mechanism. When browser sends a request it is expecting one and only one response. So if it receives more than 1 response, it either issues a warning to the user to block this behaviour or may choose to ignore the extra responses by itself. Thus these extra responses may be lost.
Having said that you have 2 options with you:
Zip all the files that you want to download and download as a single file.
You can use Popular framework Ionic.Zip.
First, keep all your files in a local directory on the server.
Then use this library to zip the entire folder.
Pseudo code:
Imports (var zip = New Ionic.Zip.ZipFile())
{
zip.AddDirectory("DirectoryOnDisk", "rootInZipFile")
Response.Clear()
Response.AddHeader("Content-Disposition", "attachment; filename=DownloadedFile.zip")
Response.ContentType = "application/zip"
zip.Save(Response.OutputStream)
Response.End()
}
Add a mechanism to issue multiple request using Javascript to get multiple responses, so browser still treats this behaviour as normal.
A normal web page will have a load of (headers) stuff set up for you already, but you don't want any of that: you want complete control over what is sent to the browser. If you cause a redirect to something which sends the headers shown in code later here, the browser will (normally) download the data.
In the code-behind you can have something like
Protected Sub btn_click(ByVal sender As Object, ByVal e As EventArgs) Handles btn.Click
Response.Redirect("~/sendfile.ashx?ref=" & enReference, False)
Context.ApplicationInstance.CompleteRequest()
End Sub
You will also need to add a generic handler (right-click on the project in Solution Explorer, Add->New Item... -> Visual Basic--Web--General choose "Generic Handler"; give it a name like sendfile.ashx) which is somewhat like
Imports System.IO
Public Class sendfile
Implements System.Web.IHttpHandler, IReadOnlySessionState
Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
Dim enReference = context.Request.QueryString("ref")
' do whatever is needed to get the report from enReference '
Dim bytes As Byte() = aReport.ServerReport.Render("WORD", Nothing, mimeType, encoding, extension, streamids, warnings)
Dim downloadName = yourfilename & "." & yourextension
context.Response.ContentType = "application/octet-stream"
context.Response.AddHeader("content-disposition", "attachment; filename=""" & downloadName & """" )
context.Response.BinaryWrite(bytes)
End Sub
ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
and you will need to work out the code to create the data to be sent.
If you don't need to use session state then you can remove the , IReadOnlySessionState part on the Implements line.
You might need to add context.Response.Flush(). If you find that the response does not have a Content-Length header, then you ought to add one so that the browser can show a meaningful download progress.

vb.net multiple webproxy in httpwebrequest

I am currently working on a VB.net project where I need to get http responses from a certain URI but the requests needs to go through http proxy which I am perfectly fine with. The problem occurred when I realised sometimes our proxy servers are not working and then the application throws an error. I want my app to check whether the proxy is working or not, if not then I want it to take another proxy from the proxy list/array. And also, please feel free to share if you have any alternative ideas.
Currently I am using this (which is static and when it throws an error I need to manually change the proxy):
Dim proxyObject As WebProxy = New WebProxy("192.168.0.10:80")
request.Proxy = proxyObject
What I want is something like this:
If WebProxy("192.168.0.10:80") is working fine Then
Execute the response
Else
Take the next proxy address from the list/array and go back to the starting
of "If"
End If
FYI: my proxies doesn't require authentication.
I apologise if I couldn't explain it properly and to be honest I'm fairly new in VB.net.
Thanks a lot for your time and patience. Appreciate your help.
Borrowing from this question
Dim urlList As New List(Of String) 'Urls stored here
For each urlString as string in urlList
If CheckProxy(urlString) Then
'Execute the response
else
Continue For 'or something else here, mark it as bad?
End If
next
Public Shared Function CheckProxy(ByVal Proxy As String) As Boolean
Dim prx As Uri = Nothing
If Uri.TryCreate(Proxy, UriKind.Absolute, prx) Then
Return CheckProxy(prx)
ElseIf Uri.TryCreate("http://" & Proxy, UriKind.Absolute, prx) Then
Return CheckProxy(prx)
Else
Return False
End If
End Function
Public Shared Function CheckProxy(ByVal Proxy As Uri) As Boolean
Dim iProxy As Socket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
iProxy.ReceiveTimeout = 500 : iProxy.SendTimeout = 500
Try
'' Connect using a timeout (1/2 second)
Dim result As IAsyncResult = iProxy.BeginConnect(Proxy.Host, Proxy.Port, Nothing, Nothing)
Dim success As Boolean = result.AsyncWaitHandle.WaitOne(500, True)
If (Not success) Then
iProxy.Close() : Return False
End If
Catch ex As Exception
Return False
End Try
Dim bytData() As Byte, strData As String
Dim iDataLen As Integer = 1024
strData = String.Format("CONNECT {0}:{1} HTTP/1.0{2}{2}", "www.google.com", 80, vbNewLine)
bytData = System.Text.ASCIIEncoding.ASCII.GetBytes(strData)
If iProxy.Connected Then
iProxy.Send(bytData, bytData.Length, SocketFlags.None)
ReDim bytData(1024)
Do
Try
iDataLen = iProxy.Receive(bytData, bytData.Length, SocketFlags.None)
Catch ex As Exception
iProxy.Close() : Return False
End Try
If iDataLen > 0 Then
strData = System.Text.ASCIIEncoding.ASCII.GetString(bytData)
Exit Do
End If
Loop
Else
Return False
End If
iProxy.Close()
Dim strAttribs() As String
strAttribs = strData.Split(" "c)
If strAttribs(1).Equals("200") Then
Return True
Else
Return False
End If
End Function

Problems With Paypal Express Checkout Integration (WEBREQUEST)

So I was struggling with making head or tail out of the PayPal documentation and always felt that something was not right with my Webrequest.
So I stripped all the code back to basic and simply submitted the request via HTTP and the PLUS side is that I now get a response back from the PayPal sandbox server where ACK=Success and TOKEN=Valid-token-value-here there are some other variables returned too, such as CORRELATIONID and TIMESTAMP.
And hence so I tried some of the webrequest samples and I simply get a blank screen instead of being redirected to Paypal for the (sandbox) customer to complete payment.
So if anyone can post their WebRequest method that would be great.
Here is the code I used for my webrequest, I'm sure its wrong but cannot pinpoint where it is going wrong.
Also, when I run the code on my localhost during debugging, everything works fine and the call is completed with SUCCESS and a TOKEN is received.
When I run it live, I recieve Error Number 5 in the Error exception and also the text `Remote host failed to connect' in the STATUS DESCRIPTION.
THIS IS THE UPDATED CODE
Function MakeWebRequest(ByVal pUseSandbox As Boolean, ByVal pRequestMethod As String, ByVal pReturnUrl As String, ByVal pCancelUrl As String, ByRef pRtnStatus As String, ByRef pRtnStatusId As HttpStatusCode, ByRef pRtnResponseString As String) As Boolean
'
Dim _sxHost As String = Nothing
Dim _sxEndpoint As String = Nothing
Dim _sxNameValCol As System.Collections.Specialized.NameValueCollection = Nothing
Dim _sxResponseCol As System.Collections.Specialized.NameValueCollection = Nothing
Dim _sxCounta As Integer = Nothing
Dim _sxParamsString As String = Nothing
'
'-> Init
_sxParamsString = ""
MakeWebRequest = False
_sxNameValCol = New System.Collections.Specialized.NameValueCollection()
_sxResponseCol = New System.Collections.Specialized.NameValueCollection()
If pUseSandbox Then
_sxHost = "http://www.sandbox.paypal.com"
_sxEndpoint = "https://api-3t.sandbox.paypal.com/nvp"
Else
_sxHost = "http://www.paypal.com"
_sxEndpoint = "https://api-3t.paypal.com/nvp"
End If
'-> Create Request
Try
'-> Key/Value Collection Params
_sxNameValCol.Add("METHOD", "SetExpressCheckout")
_sxNameValCol.Add("USER", _UserName)
_sxNameValCol.Add("PWD", _Password)
_sxNameValCol.Add("SIGNATURE", _Signature)
_sxNameValCol.Add("PAYMENTREQUEST_0_AMT", Format(_Basket.BasketTotalIncDelivery / 100, "0.00"))
_sxNameValCol.Add("PAYMENTREQUEST_0_PAYMENTACTION", "Sale")
_sxNameValCol.Add("PAYMENTREQUEST_0_CURRENCYCODE", "GBP")
_sxNameValCol.Add("RETURNURL", pReturnUrl)
_sxNameValCol.Add("CANCELURL", pCancelUrl)
_sxNameValCol.Add("REQCONFIRMSHIPPING", "0")
_sxNameValCol.Add("NOSHIPPING", "2")
_sxNameValCol.Add("LOCALECODE", "EN")
_sxNameValCol.Add("BUTTONSOURCE", "PP-ECWizard")
_sxNameValCol.Add("VERSION", "93.0")
'-> UrlEncode
For _sxCounta = 0 To _sxNameValCol.Count - 1
If _sxCounta = 0 Then
_sxParamsString = _sxParamsString & _sxNameValCol.Keys(_sxCounta) & "=" & HttpUtility.UrlEncode(_sxNameValCol(_sxCounta))
Else
_sxParamsString = _sxParamsString & "&" & _sxNameValCol.Keys(_sxCounta) & "=" & HttpUtility.UrlEncode(_sxNameValCol(_sxCounta))
End If
Next
'-> Credentials (not used)
'_sxRequest.Credentials = CredentialCache.DefaultCredentials
Try
Dim _sxRequest As WebRequest = DirectCast(System.Net.WebRequest.Create(_sxEndpoint), System.Net.HttpWebRequest)
'-> Convert request to byte-array
Dim _sxByteArray As Byte() = Encoding.UTF8.GetBytes(_sxParamsString)
_sxRequest.Method = "POST" 'Our method is post, otherwise the buffer (_sxParamsString) would be useless
_sxRequest.ContentType = "application/x-www-form-urlencoded" 'We use form contentType, for the postvars
_sxRequest.ContentLength = _sxByteArray.Length 'The length of the buffer (postvars) is used as contentlength
Dim _sxPostDataStream As System.IO.Stream = _sxRequest.GetRequestStream() 'We open a stream for writing the postvars
_sxPostDataStream.Write(_sxByteArray, 0, _sxByteArray.Length) 'Now we write, and afterwards, we close
_sxPostDataStream.Close() 'Closing is always important!
'-> Create Response
Dim _sxResponse As HttpWebResponse = DirectCast(_sxRequest.GetResponse(), HttpWebResponse)
'-> Get Response Status
pRtnStatus = _sxResponse.StatusDescription
pRtnStatusId = _sxResponse.StatusCode
'-> Reponse Stream
Dim _sxResponseStream As Stream = _sxResponse.GetResponseStream() 'Open a stream to the response
'-> Response Stream Reader
Dim _sxStreamReader As New StreamReader(_sxResponseStream) 'Open as reader for the stream
pRtnResponseString = _sxStreamReader.ReadToEnd() 'Read the response string
MakeWebRequest = True
'-> Tidy up
_sxStreamReader.Close()
_sxResponseStream.Close()
_sxResponse.Close()
_sxByteArray = Nothing
_sxPostDataStream = Nothing
_sxRequest = Nothing
_sxResponse = Nothing
_sxResponseStream = Nothing
_sxStreamReader = Nothing
Catch ex As Exception
pRtnStatusId = Err.Number
pRtnStatus = "response(" & ex.Message & ")"
Decode(pRtnResponseString, _sxResponseCol)
pRtnResponseString = Stringify(_sxResponseCol)
End Try
Catch ex As Exception
pRtnStatusId = Err.Number
pRtnStatus = "request(" & ex.Message & ")"
Decode(pRtnResponseString, _sxResponseCol)
pRtnResponseString = Stringify(_sxResponseCol)
End Try
'-> Tidy Up
_sxHost = Nothing
_sxEndpoint = Nothing
_sxNameValCol = Nothing
_sxResponseCol = Nothing
_sxCounta = Nothing
_sxParamsString = Nothing
'
End Function
OK, so it's now clear that you're not getting any response from the server because your server isn't able to connect to PayPal's servers at all. Hence, you got no server-response and the message Unable to connect to the remote server. When I tested, I got a HTTP 200 response with the following body:
TIMESTAMP=2015-07-07T09:07:39Z&CORRELATIONID=7f4d2313c9696&ACK=Failure&VERSION=93.0&BUILD=17276661&L_ERRORCODE0=10002&L_SHORTMESSAGE0=Authentication/Authorization Failed&L_LONGMESSAGE0=You do not have permissions to make this API call&L_SEVERITYCODE0=Error
Obviously that's because I tested with a blank username and password.
So, something is wrong with your server setup that's preventing you from making outside connections, either at the IIS level or due to your firewall configuration.
Without physically being present at your machine, there's not a lot we can do to track down what's blocking it, but you can try opening HTTP requests to other public websites like Google.com and see if those succeed.

How to write response into Buffer instead of rendering on Screen?

I am developing app where I need to capture an Information from Webpage after giving credentials automatically. Some how I managed to do Automatic login and redirection of page. Here is my code :
HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://abcd.com.au/categories/A_dfn/sdf");
HttpWebResponse res = req.GetResponse() as HttpWebResponse;
StringBuilder sb = new StringBuilder();
byte[] buf = new byte[10000];
Stream resStream = res.GetResponseStream();
string s = null;
int c = 0;
do
{
c = resStream.Read(buf, 0, buf.Length);
if (c != 0) {
s = ASCIIEncoding.ASCII.GetString(buf, 0, c);
sb.Append(s);
}
} while (c > 0);
string oldhead = "class=\"login_button\">";
string newhead = "class=\"login_button\"> <script type=\"text/javascript\">document.getElementById('btn').click()</script>";
sb.Replace(oldhead, newhead);
string oldbtn = "value=\"Submit\"";
string newbtn = "value=\"Submit\" id=\"btn\" ";
sb.Replace(oldbtn, newbtn);
string oldAction = "<form action=\"/login\" method=\"post\">";
string newAction = "<form action=\"https://abcd.com.au/login?orig_req_url=%2Fcategories/A_dfn/sdf\" method=\"post\">";
sb.Replace(oldAction, newAction);
string oldUsername = "<input id=\"login_email\" type=\"text\" name=\"user[email_address]\" class=\"textBox\" value=\"\">";
string newUserName = "<input id=\"login_email\" type=\"text\" name=\"user[email_address]\" class=\"textBox\" value=\"abc#xyz.com.au\">";
sb.Replace(oldUsername, newUserName);
string oldPass = "<input id=\"login_password\" type=\"password\" name=\"user[password]\" class=\"textBox\" value=\"\">";
string newPass = "<input id=\"login_password\" type=\"password\" name=\"user[password]\" class=\"textBox\" value=\"abc\">";
sb.Replace(oldPass,newPass);
Response.Write(sb);
This is show me expected output as I want by rendering page(Response.write(sb)). But, now I want to do same thing without redirecting to "https://abcd.com.au/login?orig_req_url=%2Fcategories/A_dfn/sdf" and want to do more stuff on this. I expect to get output of Response.Write(sb) in some buffer. Is it possible to do?
Here is example, that explains exactly what I want to do.
I am looking for an product's qty say name : Screw 15mm, this resides in page https://abcd.com.au/%2Fcategories/A_dfn/sdf.
So, I am requesting this url first, but as need login to access that page, its redirecting me to login page, filling username and password, pressing login button by using javascript,and then redirected to Originally Requested page. And on this page I want to find for that product, and return information to my web app.
All this I want to do without showing to user.
I just want to show retrieved information.
Thanks.
What you are looking for is a persisted session. Your approach towards this problem is incorrect. You are triggering the submit on the client-side. What you are trying to achieve should be done on the server-side.
The key to your scenario is to persist (store) the session & cookies set by the login page; then before your next request for the product info, inject the credential into the requesting webRequest.
Use the WebRequest object to load the login page.
Store any info (cookies) sent by the login page Response header.
create a new WebRequest object with the provided Response header, inject in userid/password.
Store any credentials returned by the Response.
Proceed to request for the quote info.
There is no generic way to do this without knowing the website you are trying to screen-scrap from. But the general step is as above. Basically, you need to create a custom class for this.
Also, you need HTMLAgilityPack to parse the HTML nodes. It is the correct method.
EDIT: Added my codes. Just so happen that I've created this class before sometime ago. So, you're in luck. However, you will need HTMLAgilityPack installed & referenced to use it. You can download HAP at: http://htmlagilitypack.codeplex.com/ If you want to do any serious screen-scraping, HAP is the de-facto standard.
Public Class clsBrowserSession
'=================================================================================================================================
'This is a special Browser Post class
' Instead of just POST to a URL as per the clsWeb.fnsPostResponse()
' clsBrowserSession allows us to LOAD a page first, persist all the cookies and variables, and then only POST to the target URL.
' The reason is that some program will drop (lets say) a SessionID as an input when you first load the page.
' and when you post, without the SessionID (variable), it will reject the POST. Thus clsBrowserSession can solve this problem.
'=================================================================================================================================
' USAGE:
' Dim voBrowserSession As New clsBrowserSession
' voBrowserSession.sbLoadPage("https://xxx.yyy.net.my/publicncdenq/index.htm")
' voBrowserSession.proFormElements("UserID") = "myID"
' voBrowserSession.proFormElements("Password") = "myPassword"
' Dim vsResponseHTML As String = voBrowserSession.Post("https://xxx.yyy.net.my/publicncdenq/index.htm")
Private vbIsPostingInProgress As Boolean
Public voCookies As System.Net.CookieCollection
Public proHTMLDoc As HtmlAgilityPack.HtmlDocument
Public proFormElements As clsFormElementCollection
Public Sub sbLoadPage(pvsURL As String)
vbIsPostingInProgress = False
fnoCreateWebRequestObject().Load(pvsURL)
End Sub
Public Function Post(pvsURL As String) As String
vbIsPostingInProgress = True
fnoCreateWebRequestObject().Load(pvsURL, "POST")
Return proHTMLDoc.DocumentNode.InnerHtml
End Function
Private Function fnoCreateWebRequestObject() As HtmlAgilityPack.HtmlWeb
Dim voWeb As New HtmlAgilityPack.HtmlWeb
voWeb.UseCookies = True
voWeb.PreRequest = New HtmlAgilityPack.HtmlWeb.PreRequestHandler(AddressOf event_OnPreRequest)
voWeb.PostResponse = New HtmlAgilityPack.HtmlWeb.PostResponseHandler(AddressOf event_OnAfterResponse)
voWeb.PreHandleDocument = New HtmlAgilityPack.HtmlWeb.PreHandleDocumentHandler(AddressOf event_OnPreHandleDocument)
Return voWeb
End Function
Private Sub sbAddPostDataTo(pvoRequest As Net.HttpWebRequest)
Dim vsPayload As String = proFormElements.fnsAssemblePostPayload()
Dim vabyteBuffer As Byte() = Text.Encoding.UTF8.GetBytes(vsPayload.ToCharArray())
pvoRequest.ContentLength = vabyteBuffer.Length
pvoRequest.ContentType = "application/x-www-form-urlencoded"
pvoRequest.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97 Safari/537.11"
pvoRequest.GetRequestStream().Write(vabyteBuffer, 0, vabyteBuffer.Length)
End Sub
Private Sub sbAddvoCookiesTo(pvoRequest As Net.HttpWebRequest)
If (Not IsNothing(voCookies)) Then
If voCookies.Count > 0 Then pvoRequest.CookieContainer.Add(voCookies)
End If
End Sub
Private Sub sbSaveCookiesFrom(pvoResponse As Net.HttpWebResponse)
If pvoResponse.Cookies.Count > 0 Then
If IsNothing(voCookies) Then voCookies = New Net.CookieCollection
voCookies.Add(pvoResponse.Cookies)
End If
End Sub
Private Sub sbSaveHtmlDocument(pvoHTMLDocument As HtmlAgilityPack.HtmlDocument)
proHTMLDoc = pvoHTMLDocument
proFormElements = New clsFormElementCollection(proHTMLDoc)
End Sub
Protected Function event_OnPreRequest(pvoRequest As Net.HttpWebRequest) As Boolean
sbAddvoCookiesTo(pvoRequest)
If vbIsPostingInProgress Then sbAddPostDataTo(pvoRequest)
Return True
End Function
Protected Sub event_OnAfterResponse(pvoRequest As System.Net.HttpWebRequest, pvoResponse As Net.HttpWebResponse)
sbSaveCookiesFrom(pvoResponse)
End Sub
Protected Sub event_OnPreHandleDocument(pvoHTMLDocument As HtmlAgilityPack.HtmlDocument)
sbSaveHtmlDocument(pvoHTMLDocument)
End Sub
'-----------------------------------------------------------------------------------------------------
'Form Elements class
' Note: This element class will only capture (any) INPUT elements only, which should be enough
' for most cases. It can be easily modified to add other SELECT, TEXTAREA, etc voInputs
'-----------------------------------------------------------------------------------------------------
Public Class clsFormElementCollection
Inherits Dictionary(Of String, String)
Public Sub New(htmlDoc As HtmlAgilityPack.HtmlDocument)
Dim voInputs As Collections.Generic.IEnumerable(Of HtmlAgilityPack.HtmlNode) = htmlDoc.DocumentNode.Descendants("input")
For Each voInput As HtmlAgilityPack.HtmlNode In voInputs
Dim vsName = voInput.GetAttributeValue("name", "undefined")
Dim vsValue = voInput.GetAttributeValue("value", "")
If vsName <> "undefined" Then Add(vsName, vsValue)
Next
End Sub
Public Function fnsAssemblePostPayload() As String
Dim sb As New Text.StringBuilder
For Each voKeyValuePair In Me
Dim vsValue = System.Web.HttpUtility.UrlEncode(voKeyValuePair.Value)
sb.Append("&" & voKeyValuePair.Key & "=" & vsValue)
Next
Return sb.ToString.Substring(1)
End Function
End Class
End Class
Just make the above into a class object and instantiate it. The usage example is in the comment. You want the vsResponseHTML string.

Upload files asynchronously with ASP.NET

I'm trying to make an asynchronous upload operation but I got this error message:
Error occurred, info=An exception
occurred during a WebClient request`.
Here's the upload function:
Private Sub UploadFile()
Dim uploads As HttpFileCollection
uploads = HttpContext.Current.Request.Files
Dim uri As Uri = New Uri("C:\UploadedUserFiles\")
Dim client = New WebClient
AddHandler client.UploadFileCompleted, AddressOf UploadFile_OnCompleted
For i As Integer = 0 To (uploads.Count - 1)
If (uploads(i).ContentLength > 0) Then
Dim c As String = System.IO.Path.GetFileName(uploads(i).FileName)
Try
client.UploadFileAsync(uri, c)
Catch Exp As Exception
End Try
End If
Next i
End Sub
Public Sub UploadFile_OnCompleted(ByVal sender As Object, ByVal e As System.ComponentModel.AsyncCompletedEventArgs)
Dim client As WebClient = CType(e.UserState, WebClient)
If (e.Cancelled) Then
labMessage.Text = "upload files was cancelled"
End If
If Not (e.Error Is Nothing) Then
labMessage.Text = "Error occured, info=" + e.Error.Message
Else
labMessage.Text = "File uploaded successfully"
End If
End Sub
Update 1:
Private Sub UploadFile()
Dim uploads As HttpFileCollection
Dim fileToUpload = "C:\Demo\dummy.doc"
Dim uri As Uri = New Uri("C:\UploadedUserFiles\")
Dim client = New WebClient
AddHandler client.UploadFileCompleted, AddressOf UploadFile_OnCompleted
client.UploadFileAsync(uri, fileToUpload)
End Sub
client.UploadFileAsync(uri, fileToUpload) is throwing this error message
Error occured, info=System.Net.WebException: The request was aborted: The request was canceled. at System.Net.FileWebRequest.EndGetResponse(IAsyncResult asyncResult) at System.Net.WebClient.GetWebResponse(WebRequest request, IAsyncResult result) at System.Net.WebClient.DownloadBitsResponseCallback(IAsyncResult result)
By calling GetFileName you're truncating whatever path information was there. You should provide UploadFileAsync with a full path name.
Also, replace e.Error.Message with just e.Error so you get the full error details including inner exceptions. This will provide more info and probably lead you to the answer.
Dim uri As Uri = New Uri("C:\UploadedUserFiles\")
The above statement is wrong, how come you have Uri as a file system path, it should be "http://" or "https://" , if you are trying to upload it to your local asp.net web site project then you must have a url something like http://localhost:PORT/UploadedUserFiles ... and you will know port number when you execute project.
Dim uri As Uri = New Uri("http://localhost:PORT/Upload.aspx")
Try this:
1) Create a new class MyWebClient.
Class MyWebClient
Inherits WebClient
Protected Overrides Function GetWebRequest(address As Uri) As WebRequest
Dim req = MyBase.GetWebRequest(address)
Dim httpReq = TryCast(req, HttpWebRequest)
If httpReq IsNot Nothing Then
httpReq.KeepAlive = False
End If
Return req
End Function
End Class
2) Use this class instead of the default WebRequest.
Private Sub UploadFile()
Dim uploads As HttpFileCollection
uploads = HttpContext.Current.Request.Files
Dim uri As Uri = New Uri("C:\UploadedUserFiles\")
Dim client = New MyWebClient
AddHandler ...
I hope this helps.
From the reference to HttpContext.Current.Request.Files I am assuming that your are running the code in a web project. You don't have to use WebClient to save the file to your disk. All you have to do is this:
Private Sub UploadFile()
Dim uploads As HttpFileCollection
uploads = HttpContext.Current.Request.Files
Dim path As String = "C:\UploadedUserFiles\"
For i As Integer = 0 To (uploads.Count - 1)
If (uploads(i).ContentLength > 0) Then
Dim p As String = System.IO.Path.Combine(path, System.IO.Path.GetFileName(uploads(i).FileName))
uploads(i).SaveAs(p)
End If
Next i
End Sub
I'm not that good with VB.. so there might be syntax problems :) bear with me..
You can't upload files from the ASP.NET web request asyncronously via this mechanism. The file is actually in the body of the http request so it is already on the server. Request.Files provides a stream to the files that are already on the server.
You could use something like Silverlight or Flash from the client side.
You might want to investigate the AJAX Control Toolkit and use the AsyncFileUpload control.
The control has a server side event when upload is complete. (UploadedComplete)
It also has a SaveAs(string filename) method for the uploaded file.
Simple Usage:
Markup
<asp:AsyncFileUpload ID="upload" runat="server" OnUploadedComplete="displayFile"/>
Code Behind
protected void displayFile(object sender, AjaxControlToolkit.AsyncFileUploadEventArgs e)
{
upload.SaveAs("C:\\text.txt");//server needs permission
}
Try to add Header information to the WebClient Object as below :
With webClient
.Headers.Add("Content-Type", Web.MimeMapping.GetMimeMapping("C:\filename.txt"))
.Headers.Add("Keep-Alive", "true")
.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)")
.Credentials = New Net.NetworkCredential("UserName", "password")
End With

Resources