WebClient.UploadData "The underlying connection was closed" - vb.net

I'm trying to upload a file from an FTP site to Basecamp using the Basecamp API. I'm using a simple console application. Here's my code:
Try
Dim accountID As String = ConfigurationManager.AppSettings("BaseCampID")
Dim projectID As Integer = 9999999
Dim folderName As String = "XXXXX/XXXXX"
Dim fileName As String = "XXX.zip"
'The URL to access the attachment method of the API
Dim apiURL = String.Format("https://basecamp.com/{0}/api/v1/projects/{1}/attachments.json", accountID, projectID)
'Get the file from the FTP server as a byte array
Dim fileBytes As Byte() = GetFileBytes(String.Format("{0}\\{1}", folderName, fileName))
'Initialize the WebClient object
Dim client As New WebClient()
client.Headers.Add("Content-Type", "application/zip")
'Need to provide a user-agent with a URL or email address
client.Headers.Add("User-Agent", "Basecamp Upload (email#email.com)")
'Keep the connection alive so it doesn't close
client.Headers.Add("Keep-Alive", "true")
'Provide the Basecamp credentials
client.Credentials = New NetworkCredential("username", "password")
'Upload the file as a byte array to the API, and get the response
Dim responseStr As Byte() = client.UploadData(apiURL, "POST", fileBytes)
'Convert the JSON response to a BaseCampAttachment object
Dim attachment As BaseCampAttachment
attachment = JSonHelper.FromJSon(Of BaseCampAttachment)(Encoding.Default.GetString(responseStr))
Catch ex As Exception
Console.WriteLine(ex.Message)
Finally
Console.ReadLine()
End Try
But whenever it calls client.UploadData, I get the error message "The underlying connection was closed: The connection was closed unexpectedly." I ran into this issue earlier and thought I solved it by adding the "Keep-Alive" header, but it's not working anymore. The API works if I upload a local file with client.UploadFile, but I'd like to just upload the file from they byte array from the FTP rather than downloading the file locally then uploading it to Basecamp.
Any thoughts would be greatly appreciated. Thanks!

I never figured out what was wrong with the WebClient call, but I ended up using a Basecamp API wrapper from https://basecampwrapper.codeplex.com. That wrapper uses HTTPRequest and HTTPResponse instead of WebClient.UploadData. It's also much easier to just use that wrapper than to try writing my own code from scratch.

Related

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);

Anonymous HTTP Web Request

I created http request application to test my web site qulatiy (see below).
Dim Request As HttpWebRequest = WebRequest.Create(webAddress)
Dim Response As HttpWebResponse = Request.GetResponse()
Request.Method = "Get"
Dim Reader As New StreamReader(Response.GetResponseStream)
Dim Html As String = Reader.ReadToEnd()
In this case, I would like to create anonymous request without catching the response. How can I do that?
To do so, u have to get a little low level , working with sockets
TcpCient in this case
Sample code
Imports System.Net.Sockets
Module Module1
Sub Main()
Dim tcpcli = New TcpClient()
tcpcli.Connect("google.co.in", 80)
Dim stream As NetworkStream = tcpcli.GetStream()
Dim reqdata As String = String.Format("GET / HTTP/1.1{0}Host: www.google.co.in{0}Connection: Close{0}{0}", vbCrLf)
Dim reqbytes() As Byte = Text.Encoding.ASCII.GetBytes(reqdata)
stream.Write(reqbytes, 0, reqbytes.Length)
stream.Close()
stream.Dispose()
tcpcli.Close()
End Sub
End Module
Network capture via wireshark (no response received)
You can make a web request anonymously by using ProxySharp. It basically makes the web request behind a random vpn each time. This makes it look like the request is coming from a different IP address on each request.

How to use HttpWebRequest to download file

Trying to download file in code.
Current code:
Dim uri As New UriBuilder
uri.UserName = "xxx"
uri.Password = "xxx"
uri.Host = "xxx"
uri.Path = "xxx.aspx?q=65"
Dim request As HttpWebRequest = DirectCast(WebRequest.Create(uri.Uri), HttpWebRequest)
request.AllowAutoRedirect = True
request = DirectCast(WebRequest.Create(DownloadUrlIn), HttpWebRequest)
request.Timeout = 10000
'request.AllowWriteStreamBuffering = True
Dim response As HttpWebResponse = Nothing
response = DirectCast(request.GetResponse(), HttpWebResponse)
Dim s As Stream = response.GetResponseStream()
'Write to disk
Dim fs As New FileStream("c:\xxx.pdf", FileMode.Create)
Dim read As Byte() = New Byte(255) {}
Dim count As Integer = s.Read(read, 0, read.Length)
While count > 0
fs.Write(read, 0, count)
count = s.Read(read, 0, read.Length)
End While
'Close everything
fs.Close()
s.Close()
response.Close()
Running this code and checking the response.ResponseUri indicates im being redirected back to the login page and not to the pdf file.
For some reason its not authorising access what could I be missing as Im sending the user name and password in the uri? Thanks for your help
You don't need all of that code to download a file from the net
just use the WebClient class and its DownloadFile method
you should check and see if the site requires cookies (most do), i'd use a packet analyzer and run your code and see exactly what the server is returning. use fiddler or http analyzer to log packets
With UWP, this has become a more pertinent question as UWP does not have a WebClient. The correct answer to this question is if you are being re-directed to the login page, then there must be an issue with your credentials OR the setting (or lack of) header for the HttpWebRequest.
According to Microsoft, the request for downloading is sent with the call to GetResponse() on the HttpWebRequest, therefore the downloaded file SHOULD be in the stream in the response (returned by the GetResponse() call mentioned above).

how to read xml from remote url in vb.net

i am working in a project in that i want to read some data from the remote url can any one help me how to do this function
You can use a WebRequest to retrieve the XML from the remote site; then you can parse the contents into an XmlDocument object.
' Create a WebRequest to the remote site
Dim request As System.Net.HttpWebRequest = System.Net.HttpWebRequest.Create("http://www.domain.com/fetch.xml")
' NB! Use the following line ONLY if the website is protected
request.Credentials = New System.Net.NetworkCredential("username", "password")
' Call the remote site, and parse the data in a response object
Dim response As System.Net.HttpWebResponse = request.GetResponse()
' Check if the response is OK (status code 200)
If response.StatusCode = System.Net.HttpStatusCode.OK Then
' Parse the contents from the response to a stream object
Dim stream As System.IO.Stream = response.GetResponseStream()
' Create a reader for the stream object
Dim reader As New System.IO.StreamReader(stream)
' Read from the stream object using the reader, put the contents in a string
Dim contents As String = reader.ReadToEnd()
' Create a new, empty XML document
Dim document As New System.Xml.XmlDocument()
' Load the contents into the XML document
document.LoadXml(contents)
' Now you have a XmlDocument object that contains the XML from the remote site, you can
' use the objects and methods in the System.Xml namespace to read the document
Else
' If the call to the remote site fails, you'll have to handle this. There can be many reasons, ie. the
' remote site does not respond (code 404) or your username and password were incorrect (code 401)
'
' See the codes in the System.Net.HttpStatusCode enumerator
Throw New Exception("Could not retrieve document from the URL, response code: " & response.StatusCode)
End If
Along with what #Jon Skeet said there's also the built-in WebClient:
Dim MyData As String
Try
Using WC As New System.Net.WebClient()
MyData = WC.DownloadString("http://www.example.com/text.xml")
End Using
Catch ex As Exception
'Error downloading
End Try
Have you tried using XDocument.Load or XmlDocument.Load?
If those don't do what you want, please give more details.
try this
http://www.codeproject.com/Tips/992109/Parsing-Reading-XML-from-URL-in-VB-NET
There are some useful examples provided with it. Hope this helps...