Get XML body of a 400 or 500 HTTP XML response - c#

Long story short, I am sending an XML HTTP post request to an application server, and I am getting back a response, also in the form of XML HTTP.
I have a test site available to me which allows me to see what the server's actual response is, visually, in the form of XML, but I cannot access this XML from my C# code the way it is.
The XML coming back from the application server in my test case looks like this:
<Error><Message>StringErrorMessage</Message></Error>
However, I have had no luck accessing this basic XML to retrieve the value of "StringErrorMessage" for the creation of a detailed error report.
... More code above, all wrapped in a try{}...
_response = Serializer.DeserializeObject<T>(ObjectRequest.GetResponse().GetResponseStream());
}
catch (System.Net.WebException exceptionParameter)
{
var response = (HttpWebResponse)exceptionParameter.Response;
string webExceptionStatus = exceptionParameter.Message;
_exception = exceptionParameter;
return false;
}
I have consulted
C# - Getting the response body from a 403 error
and
Get response body on 400 HTTP response in Android?
The first link's solution doesn't seem to give me access to the basic XML as part of any response object's properties. I am almost positive that there must be a byte[] in there somewhere (in the response, or in the exception object) that can be converted into a char[], which can be converted to a string, which can be converted to my XML body, but I have not been able to find it. The second link's solution is not exactly viable for me because I have to get the response body back in the form of XML, as it might not be an error, but an object that must be deserialized. This particular side of things, I cannot change.
Any advice would be very much appreciated.
- Eli
EDIT: Just wanted to clarify that my basic code is working okay for non-error situations, and is deserializing the XML just fine. It's when my code encounters a HTTP 400 or an HTTP 500 error, where accessing the XML from the catch statement becomes a problem, because my code immediately throws an exception.

The body of a HTTP message (the XML in your case) can be retrieved with the GetResponseStream method of the HttpWebResponse object you have. And, since it's a stream, you can for instance read it with a StreamReader, like so:
HttpWebResponse myWebResponse; // Get this from whereever you want
Stream responseStream = myWebResponse.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
string niceStringForYou = reader.ReadToEnd();
...and from that point on, you can do whatever to it.
If you're absolutely sure it's always gonna be XML you get back from the service, you can probably even use an XmlReader to get XML directly from the stream:
XmlReader foo = XmlReader.Create(responseStream);
Comment to edit: As long as you have the HttpWebResponse object, reading it's response stream (GetResponseStream()) should work. And as you point out in your own code, you can get the HttpWebResponse by looking at (HttpWebResponse)exceptionParameter.Response.

Related

AspNetCore.Mvc 2.2 return error if response body length exceeds threshold

I have an AspNet.Core.Mvc REST API that is routed through a proxy gateway. The gateway has a limit of 10mb for the response body. If the body is over that threshold it returns 500 Internal Server Error.
My goal:
To check the size of the response body before returning from my API project and if it is over that threshold, return a BadRequest error instead, with a helpful error message in the response body content. Something like, "The response is too large. Try narrowing your request."
I've tried handling this in middleware, where the byte size of the body is known, but this is too late and the framework prevents this. I've tried working around this, something like this where you swap out the Body temporarily with a MemoryStream:
Modify middleware response
However, the status code is already set to 200 at that point and the framework throws an error if you try to change it. Here is the code snippet from the middleware where it copies the new response stream to the original body:
// Replace the body with a BadRequest error notifying user that the response
// was too large and they should narrow down their search parameters.
var errorStream = new MemoryStream();
var sw = new StreamWriter(errorStream);
sw.Write("Response exceeds maximum size. Try narrowing request parameters or setting a smaller page size if applicable.");
sw.Flush();
errorStream.Position = 0;
await errorStream.CopyToAsync(originalBody);
httpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; // throws exception!
I've also tried to handle it in the Controller method itself before returning, by serializing the response content to json, then converting the json string to bytes to check the size:
string json = JsonConvert.SerializeObject(value, jsonSerializerSettings);
byte[] bytes = Encoding.UTF8.GetBytes(json);
But that is all work that the framework will do for me, and seems wasteful (and frankly ugly). Is there a way to set this as the response and return it from the Controller? Maybe I can create a base class for the Controller that all API methods can use that will do this logic?
This all seems like a lot of trouble for something seemingly simple. I'm hoping someone here has a better solution.

Accept SOAP requst in ASP.NET Webservice

I'm trying to receive a SOAP request on an ASP.NET webservice but I'm stucking here right now.
The first thing I tried was to just receive a simple string in my webservice but my webservice denied that request, because it was a "dangerous request".
The second thing I tried was to use XmlDocument and XElement as input date type but when I try that I get an IndexOutOfRangeException in SoapUI and can't call that method simply in the browser.
Is there any trick to accept SOAP requests in the WebMethod?
To make it easier to understand, I'm looking for a solution like that:
[WebMethod]
public XmlDocument Method(string soapRequest)
{
XmlDocument xmlAnswer = doSomethingWithRequest(soapRequest);
return xmlAnswer;
}
Unfortunately I couldn't find any way to do it with such a simple solution like I asked for. I tried XmlElement how it is mentioned in this (very old) article.
I did it now in that way:
// Create array for holding request in bytes
byte[] inputStream = new byte[HttpContext.Current.Request.ContentLength];
// Read the entire request input stream
HttpContext.Current.Request.InputStream.Read(inputStream, 0, inputStream.Length);
// Set stream position back to beginning
HttpContext.Current.Request.InputStream.Position = 0;
// Get the XML request
string xmlRequestString = Encoding.UTF8.GetString(inputStream);
And that works fine for me.

how c# application can retrieve data from php in an efficient manner

Below is my php code which works fine:
<?php
//This script checks the id and code of the already registered user from the database. If correct it returns the other details otherwise the respective error
//starting session
session_start();
//catching data from client
$id=$_POST['id'];
$code=$_POST['code'];
if($id&&$code)//checking if the data is not empty
{
//Connecting to server
($connect=mysqli_connect('localhost','root','','ohhell')) or exit("Connection Failed");
//Selecting user for given id
$result=mysqli_query($connect,"SELECT * FROM users WHERE id='$id'");
//Counting number of rows
$numrows=mysqli_num_rows($result);
if($numrows!=0)
{
//Creating associative array
$row=mysqli_fetch_assoc($result);
//freeing result set
mysqli_free_result($result);
//fetching code from database
$db_code=$row['code'];
$code=md5($code);
//checking if the codes match
if($code==$db_code)
{
//change status
mysqli_query($connect,"UPDATE users SET status='yellow' WHERE id='$id'");
$_SESSION['id']=$row['id'];
$_SESSION['name']=$row['name'];
$_SESSION['location']=$row['location'];
$name=$row['name'];
$location=$row['location'];
//closing connection
mysqli_close($connect);
//returning values to client
exit("$name\n$location");//Successful Login. Client can now create an object and switch the screen
}
else
{
exit("Invalid Player Code");//Unsuccessful Login
}
}
else
exit("Invalid Player ID");//Unsuccessful Login
}
else
exit("Incomplete Details");//Unsuccessful Login
?>
It returns the respective error message or the corresponding details of the player to the c# client. Below is the client side code to receive the data:
WebRequest request = WebRequest.Create(URL);
Stream dataStream;
WebResponse response;
StreamReader reader;
response = request.GetResponse();
dataStream = response.GetResponseStream();
reader = new StreamReader(dataStream);
responseFromServer = reader.ReadToEnd();
reader.Close();
dataStream.Close();
response.Close();
After receiving the data successfully the c# client separates both the data with the help of "\n" and then makes an object of a class and fill the received data to the respective data members of that class.
Now here comes the problem, since I am testing now everything is working fine. But, my question is that, as the data being read is going to be in the form of string, how can I make sure at the client side that the data is actually received successfully and the string that is retrieved actually contains the data and not the error message.
I mean suppose if an internal error occurs while connecting to php or any other network error returns the corresponding error that too would be in the form of string, now how I am going to differentiate that whether the the client app should start separating the data from the string to make the object or it should terminate with an error.
For the errors that I have included in my php I can use respective if() conditions in the c# client but that's not a proper way as the errors are not guaranteed to be limited to the considered errors in the php script. There might be a numerous number of errors that can be returned so what approach should be taken in this case to actually differentiate between the error and real data.
On possible approach is to prepend a signal say "1" to the data before sending it and to test for the signal at the client's side whether the received string starts with a "1". If yes then going for the separation else displaying the corresponding error message. But this approach is also not optimal as in the case the if the error itself starts with 1, it will fail.
So what should be actually done to send data to c# in an optimal way through a php script?
Sorry for the long description! Waiting for assistance!!!
Thanks a million billion trillion...:)
You could use http status codes to indicate error conditions.
It seems currently you're only using 200 OK (by default), but e.g. Invalid Player Code could result in a 401 Unauthorized or 403 Forbidden (if that's meant for some kind of authorization).
On the c# side you'd get that status code via the HttpWebResponse.StatusCode property
You can use HTTP Status codes to determine weather or not an error occured.
You php could set the respective HTTP header if an error occurs during the run of said php script i.e. using http_response_code.
If the Startus code is okay, you can parse the response (as said in the comments, using json) and retrieve the results. In case an error occured in the network communication, you produce the respective error yourself in the client. If an error occured in PHP, you retrieve the error by also parsing the response, thereby retrieving the error message.
Simple Example in PHP
$response = array();
$responseCode = null;
try {
// some code is executed
$responseCode = 200;
}
catch (Exception $e) {
// an error occured and we have to add it to our response
$response['error'] = array('errorcode' => $e->getCode(), 'error' => $e->getMessage());
$responseCode = 500;
}
http_response_code($responseCode);
echo(json_encode($response ));
Now in your c#, simply check the header. If it is 500 (meaning an error occured), json_decode the result and get the error. If it is 200 (meaning OK), json_encode the result. If it is anything else, responde to it according to the linkes HTTP Error Code list.
I refer to the comment-question of Vikas Prasad: "#ReeCube can I achieve all my requirements for the program trying JSON or XML. If yes can you point me to specific tutorials. I have no idea about these two. Also which one to prefer among both?"
JSON or XML are just the way how you transfer the data and how you read them after, you need php and c# to use JSON or XML. I prefer JSON but im not sure how well it's working on C#, I've never tested it.
Here you can find an JSON API for C#.
But first you should add JSON for your PHP-server. On PHP, JSON is very easy to use, there is an json_encode and json_decode function. In your case, you just need the json_encode function, because on the server side, you just want to generate the JSON for the client. How to use json_encode is very well supported by Google and the PHP documentation, but if you have questions, just ask in a comment.
Here is a little example:
<?php
$arr = array('a' => 1, 'b' => 2, 'c' => 3, 'd' => 4, 'e' => 5);
echo json_encode($arr);
?>

How to set encoding in C#?

I have a problem with encoding, I want to set encoding for example to HttpWebResponse resp, everywhere where I look it says something like that resp.ContentEncoding = Encoding.UTF8, but in practice that is wrong, because it says that ContentEncoding is a read-only property, please help me.
You need to differentiate between two similar-sounding but very different classes:
HttpWebReponse is the response received in code from a web request. In other words, you don't get to set the data on it, because it was sent by another server.
HttpResponse is the response your code is sending from ASP.NET. This is the object you get to write your response data to... and the ContentEncoding property is writable.

System.Net.HttpWebResponse Returning System.IO.Stream.NullStream

I have a case where the HttpWebResponse.GetResponseStream() returns a System.Net.NullStream even though examination of the HttpWebResponse object reveals that its underlying m_ConnectStream is an instance of System.Net.ConnectStream and the ContentLength property matches exactly the length of the content returned from the server. I also poked around in the Watch window and found my data but can't remember where I found it, but I KNOW my response data is there, the runtime just won't let me at it!
The only thing that is different from other successful scenarios is that the HttpWebRequest verb is "HEAD". I'm implementing a highly RESTful web service and wanting to use "HEAD" to request metadata for resources.
Figured it out:
Found the following .Net Fx Source Code (in HttpWebResponse Class):
/// <devdoc>
/// <para>Gets the stream used for reading the body of the response from the
/// server.</para>
/// </devdoc>
public override Stream GetResponseStream()
{
if (Logging.On)
Logging.Enter(Logging.Web, this, "GetResponseStream", "");
CheckDisposed();
if (!CanGetResponseStream()) {
// give a blank stream in the HEAD case, which = 0 bytes of data
if (Logging.On)
Logging.Exit(Logging.Web, this, "GetResponseStream",
Stream.Null);
return Stream.Null;
}
if (Logging.On)
Logging.PrintInfo(Logging.Web,
"ContentLength=" + m_ContentLength);
if (Logging.On)
Logging.Exit(Logging.Web, this, "GetResponseStream",
m_ConnectStream);
return m_ConnectStream;
}
As you can see it explicitly returns a null stream for "HEAD" requests. "Why would it do that?" I ask.
I found this at http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html:
9.4 HEAD
The HEAD method is identical to GET except that the server MUST NOT return a message-body in the response. The metainformation contained in the HTTP headers in response to a HEAD request SHOULD be identical to the information sent in response to a GET request. This method can be used for obtaining metainformation about the entity implied by the request without transferring the entity-body itself. This method is often used for testing hypertext links for validity, accessibility, and recent modification.
Wow. I took from the Richardson and Ruby RESTful Web Services book that you might be clever and respond to a "HEAD" request with a blank XHTML Form that would fully describe the structure of a resource's elements including requiredness, datatype, length etc. using all of the XHTML(5) form field attributes. After reading the HTTP spec, however, it is clear that all 'HEAD' response data has to go in the HTTP headers.
Oh well, you learn something new everyday ...

Categories