Ask a questionAsk a question
 

AnswerHelp with Net.WebRequest/WebResponse

  • Thursday, November 05, 2009 6:44 PMAndrewR73 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     
    We have some legacy code which makes use of the MS XML Core Services ("Msxml2.XMLHTTP.3.0") and needed to be upgraded/updated.  The whole purpose of the legacy code was to post some data to a remote server over HTTPS and get the response it returned.  They way I have always done this in .Net is to use the Net.WebRequest and Net.WebResponse objects, however it seems what I came up with is not returning the same pieces of info required that the old way was.

    For example, the old way would create the object by referencing the MSXML.XMLHTTP.3.0 DLL.  Then it would execute the Open() method passing in the type as "POST", the URL of the remote server, and the username and password if applicable. It would then execute SetRequestHeader() setting the content type as "text/xml", invoke the Send() method, and then get the properties: ResponseText, Status, and StatusText. And finally, it would finish by invoking Close().

    Using the example at http://msdn.microsoft.com/en-us/library/debx8sh9.aspx as a starting point I implemented the following in a Web Service (.asmx) so it could be used by our non-.Net applications via SOAP requests:

        ''' <summary>
        ''' Gets a response from a remote server which requires credentials
        ''' </summary>
        ''' <param name="ReqURL">URL of remote server to query for response</param>
        ''' <param name="ReqTimeout">Timeout in milliseconds for the response</param>
        ''' <param name="ReqType">Content Type for the request</param>
        ''' <param name="PostData">Data or content to post in the request</param>
        ''' <param name="UserName">User Name for the secure request</param>
        ''' <param name="Password">Password for the secure request</param>
        ''' <returns>Delimited String: StatusCode ~ StatusDescr ~ ResponseText</returns>
        ''' <remarks></remarks>
        <WebMethod()> _
        Public Function GetResponsePWP(ByVal ReqURL As String, ByVal ReqTimeout As Integer, ByVal ReqType As String, ByVal PostData As String, ByVal UserName As String, ByVal Password As String) As String
            Dim Creds As New NetworkCredential() With {.UserName = UserName, .Password = Password}
            Dim DataStream As Stream
            Dim HTTPResponse As HttpWebResponse
            Dim nmsResponseText As String = ""
            Dim nmsStatusDescr As String = ""
            Dim nmsStatusCode As String = ""
            Dim Request As WebRequest
            Dim Response As WebResponse
            Dim byteArray As Byte() = Encoding.UTF8.GetBytes(PostData)

            Try
                Request = WebRequest.Create(ReqURL)
                Request.Method = "POST"
                Request.ContentType = ReqType   '"text/xml" or "text/plain"
                Request.ContentLength = byteArray.Length
                Request.Timeout = ReqTimeout
                Request.Credentials = Creds

                DataStream = Request.GetRequestStream
                DataStream.Write(byteArray, 0, byteArray.Length)
                DataStream.Flush()
                DataStream.Close()

                Response = Request.GetResponse
                HTTPResponse = CType(Response, HttpWebResponse)
                nmsStatusDescr = HTTPResponse.StatusDescription
                nmsStatusCode = CStr(HTTPResponse.StatusCode)

                DataStream = Response.GetResponseStream
                Using Reader As New StreamReader(DataStream)
                    nmsResponseText = Reader.ReadToEnd
                    Reader.Close()
                End Using

                DataStream.Close()
                Response.Close()

                Return String.Format("{0}~{1}~{2}", nmsStatusCode, nmsStatusDescr, nmsResponseText)

            Catch ex As Exception
                Return String.Format("{0}~{1}~GetResponsePWP() Failed: {2}{3}", nmsStatusCode, nmsStatusDescr, vbCrLf, ex.Message)

            End Try
        End Function


    The code works great as long as there are no errors, or invalid passwords, or it doesn't time out, etc.  For example..... I removed one of the required elements in the XML and posted it to the webservice and there seems to be a problem. It’s not returning the any content like the old way used to.

    With the old XMLHTTP method we get this:
    status=409
    statusText=Conflict
    responseText=<?xml version="1.0"?><exchange_response><error><code>24</code><name>INVALID_PATIENT_IDENTIFIER</name><description>invalid/missing patient_sid element</descr
    iption></error></exchange_response>

    Posting the same XML to the new service I get this:
    ~~GetResponsePWP() Failed: The remote server returned an error: (409) Conflict.



    Another example with a malformed XML string using old method:
    status=400
    statusText=Malformed XML
    responseText=<html><head><title>400 Malformed XML</title></head><body><h1>400 Malformed XML</h1><p /><hr /><small>Resin-3.1.s070406 (built Fri, 06 Apr 2007 04:13:31 GMT)</small></body></html>

    Result from new service:
    ~~GetResponsePWP() Failed: The remote server returned an error: (400) Bad Request.


    In short, when the Web Service encounters an error, it throws an exception but I don't get the the pieces back I was expecting.  Can someone help me understand what I am doing wrong here or how to get at the pieces in the same manner as was returned like the old way?

    Thanks!

    -- Andrew


Answers

  • Thursday, November 05, 2009 9:41 PMAndrewR73 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Took quite a bit of Googling but I eventually found the answer to this one.....

    In the code I posted, the exception (when a bad password, malformed XML, etc.) occurred on the line "Response = Request.GetResponse".  Because it pops up at this point, I didn't get the HTTPWebResponse object's properties to return. As it turns out though, if the exception is a "WebExceptionStatus.ProtocolError" the exception variable will contain a pointer to an HTTPWebResponse object that can be used to get at the values I needed!

    So, I put a Try...Catch block around the "Response = Request.GetResponse" line and all is much better:

                Try
                    Response = Request.GetResponse

                Catch ex As WebException
                    Select Case ex.Status
                        Case WebExceptionStatus.ProtocolError
                            Dim ErrResponse As HttpWebResponse = CType(ex.Response, HttpWebResponse)
                            Dim ErrResult As String = New StreamReader(ErrResponse.GetResponseStream).ReadToEnd.ToString
                            If ErrResult.Length = 0 Then ErrResult = ex.Message
                            Return String.Format("{0}~{1}~{2}", CInt(ErrResponse.StatusCode).ToString, ErrResponse.StatusDescription.ToString, ErrResult)

                        Case Else
                            Return String.Format("{0}~{1}~{2}", nmsStatusCode, nmsStatusDescr, ex.Message)

                    End Select
                End Try


    I hope this helps someone.

    -- Andrew

    • Marked As Answer byAndrewR73 Thursday, November 05, 2009 9:41 PM
    •  

All Replies

  • Thursday, November 05, 2009 9:41 PMAndrewR73 Users MedalsUsers MedalsUsers MedalsUsers MedalsUsers Medals
     Answer
    Took quite a bit of Googling but I eventually found the answer to this one.....

    In the code I posted, the exception (when a bad password, malformed XML, etc.) occurred on the line "Response = Request.GetResponse".  Because it pops up at this point, I didn't get the HTTPWebResponse object's properties to return. As it turns out though, if the exception is a "WebExceptionStatus.ProtocolError" the exception variable will contain a pointer to an HTTPWebResponse object that can be used to get at the values I needed!

    So, I put a Try...Catch block around the "Response = Request.GetResponse" line and all is much better:

                Try
                    Response = Request.GetResponse

                Catch ex As WebException
                    Select Case ex.Status
                        Case WebExceptionStatus.ProtocolError
                            Dim ErrResponse As HttpWebResponse = CType(ex.Response, HttpWebResponse)
                            Dim ErrResult As String = New StreamReader(ErrResponse.GetResponseStream).ReadToEnd.ToString
                            If ErrResult.Length = 0 Then ErrResult = ex.Message
                            Return String.Format("{0}~{1}~{2}", CInt(ErrResponse.StatusCode).ToString, ErrResponse.StatusDescription.ToString, ErrResult)

                        Case Else
                            Return String.Format("{0}~{1}~{2}", nmsStatusCode, nmsStatusDescr, ex.Message)

                    End Select
                End Try


    I hope this helps someone.

    -- Andrew

    • Marked As Answer byAndrewR73 Thursday, November 05, 2009 9:41 PM
    •