Net.WebRequest/WebResponse ?'s

  • Thread starter Thread starter Andrew Raastad
  • Start date Start date
A

Andrew Raastad

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
 
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
 
Back
Top