Track webpage downloading progress - vb.net

I'm using this piece of code for VB.NET to download the text from a website:
Dim Str As System.IO.Stream
Dim srRead As System.IO.StreamReader
Dim req As System.Net.WebRequest = System.Net.WebRequest.Create("http://www.example.com/file.txt")
Dim resp As System.Net.WebResponse = req.GetResponse
Str = resp.GetResponseStream
srRead = New System.IO.StreamReader(Str)
It is just a text file, and is rather small, so it downloads really quickly. But I do believe that in the future the file will become considerably large. Is there a way to track the downloading progress from the above method?

You can find the total length of your find in the ContentLength property of your WebResponse object. Once you have that, it's pretty easy to report progress based on the data you read from the GetResponseStream.

Related

How do you delete a file generated via webapi after returning the file as response?

I'm creating a file on the fly on a WebAPI call, and sending that file back to the client.
I think I'm misunderstanding flush/close on a FileStream:
Dim path As String = tempFolder & "\" & fileName
Dim result As New HttpResponseMessage(HttpStatusCode.OK)
Dim stream As New FileStream(path, FileMode.Open)
With result
.Content = New StreamContent(stream)
.Content.Headers.ContentDisposition = New Headers.ContentDispositionHeaderValue("attachment")
.Content.Headers.ContentDisposition.FileName = fileName
.Content.Headers.ContentType = New Headers.MediaTypeHeaderValue("application/octet-stream")
.Content.Headers.ContentLength = stream.Length
End With
'stream.Flush()
'stream.Close()
'Directory.Delete(tempFolder, True)
Return result
You can see where I've commented things out above.
Questions:
Does the stream flush/close itself?
How can I delete the tempFolder after returning the result?
On top of all this, it would be great to know how to generate the file and send it to the user without writing it to the file system first. I'm confident this is possible, but I'm not sure how. I'd love to be able to understand how to do this, and solve my current problem.
Update:
I went ahead with accepted answer, and found it to be quite simple:
Dim ReturnStream As MemoryStream = New MemoryStream()
Dim WriteStream As StreamWriter = New StreamWriter(ReturnStream)
With WriteStream
.WriteLine("...")
End With
WriteStream.Flush()
WriteStream.Close()
Dim byteArray As Byte() = ReturnStream.ToArray()
ReturnStream.Flush()
ReturnStream.Close()
Then I was able to stream the content as bytearraycontent:
With result
.Content = New ByteArrayContent(byteArray)
...
End With
On top of all this, it would be great to know how to generate the file and send it to the user without writing it to the file system first. I'm confident this is possible, but I'm not sure how. I'd love to be able to understand how to do this, and solve my current problem.
To do the same thing without writing a file to disk, you might look into the MemoryStream class. As you'd guess, it streams data from memory like the FileStream does from a file. The two main steps would be:
Take your object in memory and instead of writing it to a file, you'd serialize it into a MemoryStream using a BinaryFormatter or other method (see that topic on another StackOverflow Q here: How to convert an object to a byte array in C#).
Pass the MemoryStream to the StreamContent method, exactly the same way you're passing the FileStream now.

how can show captcha image in pictureBox

i have webbrowser control to open website
I want to get captcha image that appears on this web page to show in pictureBox.....
<img src="/alpha/captcha.php?1393609547" width="150" height="25" title="Click for another image" alt="CAPTCHA" id="asc" />
An example of this
Thanks for your help
First, I see that the image src URL is a relative URL. That means you need to make it an absolute by doing something like this:
Dim absoluteURL As String = "domain of captcha" & captchaURL
Then, you need to download the image into Bytes by doing something like this:
Dim PictureBytes As Byte()
' Convert String to a Uri
Dim address As New Uri(absoluteURL, UriKind.Absolute)
' Create the web request
Dim request As HttpWebRequest = DirectCast(WebRequest.Create(address), HttpWebRequest)
' Set type to GET
request.Method = "GET"
Try
' Get response
Dim response As HttpWebResponse = DirectCast(request.GetResponse(), HttpWebResponse)
' Get the response stream into a reader
Dim stream As Stream = response.GetResponseStream
Dim reader New BinaryReader(stream)
PictureBytes = reader.ReadBytes(stream.Length)
Finally
If Not response Is Nothing Then response.Close()
End Try
Finally, you will need to convert the bytes to a bitmap and put that bitmap in a picture box
Dim Captcha As New Bitmap(new MemoryStream(PictureBytes));
pictureBox.Image = Captcha
If you encounter any problems, just comment on this post. If this code works, please consider marking this correct and up-voting. Please note, up-voting or marking an answer correct DOES NOT subtract reputation.

Saving a base 64 encoded image in MongoDB GridFS

I have a web service that takes the content of a canvas tag and saves it into a MongoDB GridFS store.
The code below works, however it requires saving the image to disk before sending it to MongoDB.
Using postBody As Stream = Request.InputStream
' Get the body of the HTTP POST (the data:image/png)
postBody.Seek(0, SeekOrigin.Begin)
Dim imageData As String = New StreamReader(postBody).ReadToEnd
Dim base64Data = Regex.Match(imageData, "data:image/(?<type>.+?),(?<data>.+)").Groups("data").Value
Dim data As Byte() = Convert.FromBase64String(base64Data)
Using stream = New MemoryStream(data, 0, data.Length)
Dim img As System.Drawing.Image = System.Drawing.Image.FromStream(stream)
Dim directory = Server.MapPath("~/App_Data/temp/")
Dim file = String.Concat(directory, id, ".png")
img.Save(file, System.Drawing.Imaging.ImageFormat.Png)
Using fs = New FileStream(file, FileMode.Open)
db.GridFS.Upload(fs, id & ".png")
End Using
End Using
End Using
Is there a better way, perhaps without the need to persist it to disk before uploading to MongoDB?
As suggested in the comments, just use the Stream as an argument to Upload instead of writing out to file.
And also note that you do not have to convert to base64 in order to send the file via GridFS (or a plain mongo field for that matter). The input can be binary, unless of course you always want your data base64 encoded for your convenience.

Windows Phone 8 Unsupported API cannot be used by a background agent

I have built a Windows Phone 8 app which compiles and runs without any problems. However, when I run the built-in VS Store Test Kit, it brings back LOTS of errors under XAP package requirements, formatted as such:
[ERROR]: Unsupported API cannot be used by a background agent.
Assembly Microsoft.Phone.Controls.Toolkit.dll was trying to use
Microsoft.Phone.Shell.ApplicationBarIconButton.
I'm getting errors for my project dll ([projectname].dll) and the Toolkit dll. It seems to be bringing back everything, even references I'm not using (such as add_OrientationChanged).
Now I've had a look through the Unsupported APIs listed by Microsoft, and I'm not using any of them. At the bottom of the page is a list of "noteworthy APIs", the one of which I;m using is HTTPWebRequest to connect to a web service. I'm assuming this is where the problem lies, as I use this throughout the app.
Here's an example of what I'm doing with HTTPWebRequest:
Public Sub LoadRequest()
Dim request As HttpWebRequest = CType(WebRequest.Create(_ServiceURL), HttpWebRequest)
request.ContentType = "text/xml;charset=utf-8"
request.Method = "POST"
request.Headers("SOAPAction") = "<web service address>"
Start the asynchronous operation.
Dim result As IAsyncResult = _
CType(request.BeginGetRequestStream(AddressOf GetRequestsStreamCallback, request), _
IAsyncResult)
End Sub
Public Sub GetRequestsStreamCallback(ByVal asyncResult As IAsyncResult)
Dim request As HttpWebRequest = CType(asyncResult.AsyncState, HttpWebRequest)
Dim soapBody As System.Xml.Linq.XDocument = System.Xml.Linq.XDocument.Parse( _
"<soap:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' " & _
"xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'><soap:Header><[SOAP Header Here]></soap:Header>" & _
"<soap:Body><[SOAP Body Here]></soap:Body></soap:Envelope>")
'End the operation
Dim postStream As Stream = request.EndGetRequestStream(asyncResult)
'Convert the string into byte array.
Dim byteArray As Byte() = Encoding.UTF8.GetBytes(soapBody.ToString())
'Write to the stream.
postStream.Write(byteArray, 0, soapBody.ToString().Length)
postStream.Close()
Dispatcher.BeginInvoke(Sub()
Dim result As IAsyncResult = _
CType(request.BeginGetResponse(AddressOf GetRequestsResponseCallback, request), IAsyncResult)
End Sub)
End Sub
Public Sub GetRequestsResponseCallback(ByVal Result As IAsyncResult)
'Get the response
Dim request As HttpWebRequest = CType(Result.AsyncState, HttpWebRequest)
Dim response As HttpWebResponse = CType(request.EndGetResponse(Result), HttpWebResponse)
Dim streamResponse As Stream = response.GetResponseStream()
Dim streamRead As New StreamReader(streamResponse)
Dim responseString As String = streamRead.ReadToEnd()
streamResponse.Close()
streamRead.Close()
'Take action on the response
Dim Xml As XDocument = XDocument.Parse(responseString)
Dim ns As XNamespace = "<Service Address>"
etc...
End Sub
I then proceed to pull apart the XML response for the data I need for the app. Any ideas as to what the test kit isn't happy about here? I'm assuming that as it doesn't pass validation at this stage, it's likely to be rejected from the store.
Thanks in advance for any ideas.
The problem was an existing background agent I was unaware of (I took over the project from another developer). There was a reference in the WMAppManifest.xml file, which was apparently part of an early test using the Wallet, which is no longer required. Removing this reference fixed the problem.
<ExtendedTask Name="BackgroundTask">
<BackgroundServiceAgent Specifier="WalletAgent" Name="WalletAgent" Source="<ProjectName>" Type="<ProjectName>.WPWalletAgent" />
</ExtendedTask>

Empty response HTTPWebRequest: Windows Phone 8

I am making a Windows Phone app and I am trying to get JSON data from a URL. The user needs to be logged into the website (which hosts the JSON data) in order to get JSON data and I cannot use the Web Browser control to display the data and then extract the string since the browser doesn't recognize it (for some weird reason) and asks to search for an app on Store which can handle that JSON file type. (If I open the URL in desktop browser on my Windows PC, I can see the raw JSON data). I can't use normal HTTPWebRequest or WebClient as to get JSON data the login cookies needs to be set (the JSON data is user-specific) and I can't extract the cookies from Web browser control and use it with WebClient or HTTPWebRequest. So the best thing I can do is use a special internal instance of IWebRequestCreate that is used internally by the WebBrowser. By opening background HTTP requests with that class, the cookies get automatically set as if they were created/sent by the WebBrowser control. But my code is not returning the JSON data, I get blank response, as in the string resp is empty.
Below is the code:
Dim browser = New WebBrowser()
Dim brwhttp = GetType(WebRequestCreator).GetProperty("BrowserHttp")
Dim requestFactory = TryCast(brwhttp.GetValue(Browser, Nothing), IWebRequestCreate)
Dim uri = New Uri("http://api.quora.com/api/logged_in_user?fields=inbox,notifs,following,followers")
Dim req = requestFactory.Create(uri)
req.Method = "GET"
req.BeginGetResponse(New AsyncCallback(AddressOf request_Callback), req)
Private Sub request_Callback(asyncResult As IAsyncResult)
Dim webRequest As HttpWebRequest = DirectCast(asyncResult.AsyncState, HttpWebRequest)
Dim webResponse As HttpWebResponse = DirectCast(webRequest.EndGetResponse(asyncResult), HttpWebResponse)
Dim tempStream As New MemoryStream()
webResponse.GetResponseStream().CopyTo(tempStream)
Dim sr As New StreamReader(tempStream)
Dim resp As String = sr.ReadToEnd
End Sub
What's wrong?
I found that CopyTo can leave the Stream's pointer at the end of the buffer, you probably need to reset tempStream's pointer to the beginning before attempting to read it with the StreamReader, here's the code...
webResponse.GetResponseStream().CopyTo(tempStream);
tempStream.Seek(0, SeekOrigin.Begin);
Dim sr As New StreamReader(tempStream);