views:

1824

answers:

3

Hey experts -

I'm having a ridiculous time trying to get an SMS API working (ZeepMobile, if you're interested) with .NET... I've been around .NET for a few years, but with all this social networking and API stuff, I need to get into the HttpWebRequest a bit. I'm new at it, but not completely new; I was able to hook up my site to Twitter without too much fuss (ie, I was able to modify someone's code to work for me).

Anyways, the way their API works is to send an SMS message, you send them a POST and they respond back to you. I can send it just fine, but every time I do, rather than echo back something helpful to figure out what the error is, I get the Yellow Error Page Of Death (YEPOD) saying something to the effect of "The remote server returned an error: (400) Bad Request." This occurs on my line:

'...creation of httpwebrequest here...'
Dim myWebResponse As WebResponse
myWebResponse = request.GetResponse() '<--- error line

Is there any way to simply receive the error from the server rather than have the webserver throw an exception and give me the YEPOD?

Or better yet, can anyone post a working example of their Zeep code? :)

Thanks!

EDIT: Here's my whole code block:

Public Shared Function SendTextMessage(ByVal username As String, _
ByVal txt As String) As String
 Dim content As String = "user_id=" + _
username + "&body=" + Current.Server.UrlEncode(txt)

 Dim httpDate As String = DateTime.Now.ToString("r")
 Dim canonicalString As String = API_KEY & httpDate & content

 Dim encoding As New System.Text.UTF8Encoding
 Dim hmacSha As New HMACSHA1(encoding.GetBytes(SECRET_ACCESS_KEY))

 Dim hash() As Byte = hmacSha.ComputeHash(encoding.GetBytes(canonicalString))
 Dim b64 As String = Convert.ToBase64String(hash)

 'connect with zeep'
 Dim request As HttpWebRequest = CType(WebRequest.Create(_
"https://api.zeepmobile.com/messaging/2008-07-14/send_message"), HttpWebRequest)
 request.Method = "POST"
 request.ServicePoint.Expect100Continue = False

 ' set the authorization levels'
 request.Headers.Add("Authorization", "Zeep " & API_KEY & ":" & b64)
 request.ContentType = "application/x-www-form-urlencoded"
 request.ContentLength = content.Length

 ' set up and write to stream'
 Dim reqStream As New StreamWriter(request.GetRequestStream())
 reqStream.Write(content)
 reqStream.Close()
 Dim msg As String = ""
 msg = reqStream.ToString

 Dim myWebResponse As WebResponse
 Dim myResponseStream As Stream
 Dim myStreamReader As StreamReader

 myWebResponse = request.GetResponse()

 myResponseStream = myWebResponse.GetResponseStream()
 myStreamReader = New StreamReader(myResponseStream)
 msg = myStreamReader.ReadToEnd()
 myStreamReader.Close()
 myResponseStream.Close()

 ' Close the WebResponse'
 myWebResponse.Close()
 Return msg
End Function
+1  A: 

I think it's normal for a WebException to be thrown when the request returns a 4xx or 5xx code. You just need to catch it and handle it appropriately.

Have you looked at the Headers collection after the call to GetResponse?

it just throws an exception at the GetResponse... how would I check the headers after that?

Try
    myWebResponse = request.GetResponse()
Catch x As WebException
    log, cleanup, etc.
Finally
    log/inspect headers?
End Try
Tim Sylvester
i can't get that far... it just throws an exception at the GetResponse... how would I check the headers after that?
Jason
From the 400 "bad request" error code, I assumed that the exception was thrown in response to getting an error from the other server. Wouldn't an error in your code cause a 500?
Tim Sylvester
do you have actual code for checking headers? i've tried so many things by now my head is swirling... thanks :(
Jason
I'm sure I could find something, but I'm equally sure I'm not allowed to post it, sorry. If you do get a WebException, then the actual error sent from the other server should be in WebException.Response and you can find the headers for it in WebException.Response.Headers. If you get a successful response, the headers will be in myWebResponse.Headers. I don't recall if request.Headers is filled in with the ones that were actually sent, or only used to specify your own to be added.
Tim Sylvester
+2  A: 

Try this:

Dim req As HttpWebRequest = DirectCast(WebRequest.Create(url), HttpWebRequest)
'' set up request
Try
    Using response = req.GetResponse()
        '' success in here
    End Using
Catch ex As WebException
    Console.WriteLine(ex.Status)
    If ex.Response IsNot Nothing Then
        '' can use ex.Response.Status, .StatusDescription
        If ex.Response.ContentLength <> 0 Then
            Using stream = ex.Response.GetResponseStream()
                Using reader = New StreamReader(stream)
                    Console.WriteLine(reader.ReadToEnd())
                End Using
            End Using
        End If
    End If
End Try


C# version

HttpWebRequest req = (HttpWebRequest) WebRequest.Create(url);
// set up request
try {
    using (var response = req.GetResponse()) {
        // success in here
        }
}
catch (WebException ex) {
    Console.WriteLine(ex.Status);
    if (ex.Response != null) {
        // can use ex.Response.Status, .StatusDescription
        if (ex.Response.ContentLength != 0) {
            using (var stream = ex.Response.GetResponseStream()) {
                using (var reader = new StreamReader(stream)) {
                    Console.WriteLine(reader.ReadToEnd());
                }
            }
        }
    }    
}


Here's your code, modified a bit:

Try
    'connect with zeep'
    Dim request As HttpWebRequest = CType(WebRequest.Create( _
"https://api.zeepmobile.com/messaging/2008-07-14/send_message"), HttpWebRequest)
    request.Method = "POST"
    request.ServicePoint.Expect100Continue = False

    ' set the authorization levels'
    request.Headers.Add("Authorization", "Zeep " & API_KEY & ":" & b64)
    request.ContentType = "application/x-www-form-urlencoded"
    request.ContentLength = content.Length

    ' set up and write to stream'
    Using requestStream As Stream = request.GetRequestStream()
        Using requestWriter As New StreamWriter(requestStream)
            requestWriter.Write(content)
        End Using
    End Using

    Using myWebResponse As WebResponse = request.GetResponse()
        Using myResponseStream As Stream = myWebResponse.GetResponseStream()
            Using myStreamReader As StreamReader = New StreamReader(myResponseStream)
                Return myStreamReader.ReadToEnd()
            End Using
        End Using
    End Using
Catch ex As WebException
    Console.WriteLine(ex.Status)
    If ex.Response IsNot Nothing Then
        '' can use ex.Response.Status, .StatusDescription
        If ex.Response.ContentLength <> 0 Then
            Using stream = ex.Response.GetResponseStream()
                Using reader = New StreamReader(stream)
                    Console.WriteLine(reader.ReadToEnd())
                End Using
            End Using
        End If
    End If
End Try


Dumping headers:

Dim headers As WebHeaderCollection = request.Headers
' Displays the headers. Works with HttpWebResponse.Headers as well
Debug.WriteLine(headers.ToString())

' And so does this
For Each hdr As String In headers
    Dim headerMessage As String = String.Format("{0}: {1}", hdr, headers(hdr))
    Debug.WriteLine(headerMessage)
Next
John Saunders
ermm... i'm not so good w/C#... can you translate into VB?
Jason
Already there. Sorry
John Saunders
what does "Using" do in VB? never seen it before...
Jason
ok i got the VB version working and i was able to read the error message... as a bonus, is there any way to read my OUTPUT headers and everything before/as it's being sent out?
Jason
Using is like "using" in C# - it makes sure that the Dispose method gets called on what's inside it, so the first one makes sure response.Dispose is called, even if there's an exception. I'm about to post a changed version of your code.
John Saunders
thanks... your posted update to my code is pretty much what i have... I figured out why I'm getting the error, so now I need to find out what my output headers look like... any way to check to see what those look like?
Jason
You should be able to iterate over request.Headers. I don't recall what type you get back from the For Each, but you should be able to get them all.
John Saunders
thanks a lot... while it doesn't fix my issue w/getting the durn thing to work, it definitely helps me work with it by being able to see the error messages.
Jason
A: 

I am using the same code, but can anybody explain me why im getting response.ContentLength as 0 always.....

Hema