开发者

Posting small bits of data in VB.NET

Is there another way to easily make a POST request in .NET other than the WebRequest class? I have a very, VERY small piece of data I need to post:

password=theword

...but WebRequest randomly, and I mean randomly, drops the data when posting to my server. I've tested it by using a chunk of code from my server that dumps the request to a console, and I can that the client is somet开发者_如何学运维imes sending and sometimes not sending the POST data.

The code that I'm using that uses WebRequest works in another project, when talking to IIS. The server being talked to (a minimal web server in another system) responds properly every time I POST data to it through Firefox. I've got a function in the same project that fires off a GET request, and that works. It just seems like my POST function isn't completing the transaction...something I've noticed in the past when asking WebRequest to handle small strings.

Here's the code that's giving me fits. If any .NET gurus out there can point me at my mistake or suggest another web client, I'd be most appreciative. Thanks!

Private Function PostRequest(ByVal url As String, ByVal data As String) As String
    Return ControlFunctions.PostRequest(url, data, 0)
End Function

Private Function PostRequest(ByVal url As String, ByVal data As String, ByVal times As Integer) As String
    Dim req As HttpWebRequest = WebRequest.Create(url)
    Dim retval As String = ""

    req.Method = "POST"
    req.UserAgent = "TSControl"
    req.ContentType = "application/x-www-form-urlencoded"
    req.ContentLength = data.Length
    req.Headers.Add("Keep-Alive", "300")
    req.KeepAlive = True
    req.Timeout = 5000

    Try
        Dim DataStream As StreamWriter = New StreamWriter(req.GetRequestStream())
        DataStream.AutoFlush = True
        DataStream.Write(data)
        DataStream.Close()

        Dim sr As StreamReader = New StreamReader(req.GetResponse().GetResponseStream())
        retval = sr.ReadToEnd()
        sr.Close()
    Catch x As Exception
        If times < 5 Then
            Threading.Thread.Sleep(1000)
            times = times + 1
            ControlFunctions.PostRequest(url, data, times)
        Else
            ErrorMsg.Show("Could not post to server" + vbCrLf + x.Message + vbCrLf + x.StackTrace)
        End If
    End Try

    Return retval
End Function

----UPDATE---

I had to go lower to fix it, but fortunately I'd dabbled with .NET's socket libraries in times past:

Private Function PostRequest(ByVal url As String, ByVal data As String) As String
    Dim uri As New Uri(url)
    Dim read(16) As Byte
    Dim FullTime As New StringBuilder
    Dim PostReq As New StringBuilder
    Dim WebConn As New TcpClient

    PostReq.Append("POST ").Append(uri.PathAndQuery).Append(" HTTP/1.1").Append(vbCrLf)
    PostReq.Append("User-Agent: TSControl").Append(vbCrLf)
    PostReq.Append("Content-Type: application/x-www-form-urlencoded").Append(vbCrLf)
    PostReq.Append("Content-Length: ").Append(data.Length.ToString).Append(vbCrLf)
    PostReq.Append("Host: ").Append(uri.Host).Append(vbCrLf).Append(vbCrLf)
    PostReq.Append(data)

    WebConn.Connect(uri.Host, uri.Port)
    Dim WebStream As NetworkStream = WebConn.GetStream()
    Dim WebWrite As New StreamWriter(WebStream)

    WebWrite.Write(PostReq.ToString)
    WebWrite.Flush()

    Dim bytes As Integer = WebStream.Read(read, 0, read.Length)

    While bytes > 0
        FullTime.Append(Encoding.UTF8.GetString(read))
        read.Clear(read, 0, read.Length)
        bytes = WebStream.Read(read, 0, read.Length)
    End While

    ' Closes all the connections
    WebWrite.Close()
    WebStream.Close()
    WebConn.Close()

    Dim temp As String = FullTime.ToString()

    If Not temp.Length <= 0 Then
        Return temp
    Else
        Return "No page"
    End If
End Function


What if you receive a "chunked" response? how do you decode it?

That's what I have been struggling with all day today. I wouldn't be struggling too much if I was dealing with a normal web service, but I am making an application that reads eBay's API data, and eBay sends wrong chunk sizes sometimes, which makes the decoder corrupt the response (even if your decoder decodes it by HTTP 1.1 rules). After trying to decode eBay's BAD API for so many hours I finally created a function that decodes chunked http response in VB.net, and it can be easily converted to C# using one of many online tools. First you check HTTP response header if the response content type is chunked, and if so, just pass the body of the response to this function, which takes the variable by reference and manipulates it:

Public Shared Sub DechunkString(ByRef strString As String)
        Dim intChunkSize As Integer = 0
        Dim strSeperator(0) As String
        strSeperator(0) = vbCrLf

        Dim strChunks As String() = strString.Split(strSeperator, StringSplitOptions.RemoveEmptyEntries)

        strString = ""

        For Each strChunk As String In strChunks
            If strChunk.Length = intChunkSize Then ' for normal behaviour this would be enough
                strString &= strChunk
                intChunkSize = 0
                Continue For
            End If

            ' because of sometimes wrong chunk sizes let's check if the next chunk size is a valid hex, and if not, treat it as part chunk
            If strChunk.Length <= 4 Then ' this is probably a valid hex, but could have invalid characters
                Try
                    intChunkSize = CInt("&H" & strChunk.Trim())

                    If intChunkSize = 0 Then
                        Exit For
                    End If

                    Continue For
                Catch ex As Exception

                End Try
            End If

            ' if got to this point, then add the chunk to output and reset chunk size
            strString &= strChunk
            intChunkSize = 0
        Next
    End Sub

I just hope it helps some one to save a lot of time and nerves.


What do you mean when you say that ".net drops the data"?

if all you want to do is post a namevalue pair, you can do it as follows:

WebClient client = new WebClient();
NameValueCollection nv = new NameValueCollection();
nv.Add("password", "theword");
client.UploadValues(url, "POST", nv);

Note that you might have to check the order of parameters passed to UploadValues, I am not sure if this sequence is right, and am too lazy right now to look up MSDN.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜