I have a desktop client, that communicates with serverside via Http.
When server has some issues with data processing it returns description of an error in JSON in Http response body with proper Http-code (mainly it is HTTP-400).
When i read HTTP-200 response everithing's fine and this code works:
using (var response = await httpRequest.GetResponseAsync(token))
{
using (var reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8")))
{
return await reader.ReadToEndAsync();
}
}
But when an error occures and WebException is thrown and caught there is this code:
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
using (var response = (HttpWebResponse) ex.Response)
{
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream, Encoding.GetEncoding("utf-8")))
{
var json = reader.ReadToEnd();
}
}
}
}
}
I have already done something to it to maybe make it work, but the next happens:
response.ContentLength is valid (184)
but stream.Length is 0
and after that i can't read json (it's "")
I don't even know where to look, because everything looks like it should work.
What might be the problem?
After a month of almost everyday thinking I've found workaround.
The thing was that WebException.Response.GetResponseStream() returns not exactly the same stream that was obtained during request (can't find link to msdn right now) and by the time we get to catch the exception and read this stream the actual response stream is lost (or something like that, don't really know and was unable to find any info on the net, except looking into CLRCore which is now opensource).
To save the actual response until catching WebException you must set KeepAlive Property on your HttpRequest and voila, you get your response while catching exception.
So the working code looks like that:
try
{
var httpRequest = WebRequest.CreateHttp(Protocol + ServerUrl + ":" + ServerPort + ServerAppName + url);
if (HttpWebRequest.DefaultMaximumErrorResponseLength < int.MaxValue)
HttpWebRequest.DefaultMaximumErrorResponseLength = int.MaxValue;
httpRequest.ContentType = "application/json";
httpRequest.Method = method;
var encoding = Encoding.GetEncoding("utf-8");
if (httpRequest.ServicePoint != null)
{
httpRequest.ServicePoint.ConnectionLeaseTimeout = 5000;
httpRequest.ServicePoint.MaxIdleTime = 5000;
}
//----HERE--
httpRequest.KeepAlive = true;
//----------
using (var response = await httpRequest.GetResponseAsync(token))
{
using (var reader = new StreamReader(response.GetResponseStream(), encoding))
{
return await reader.ReadToEndAsync();
}
}
}
catch (WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
{
using (var response = (HttpWebResponse)ex.Response)
{
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream, Encoding.GetEncoding("utf-8")))
{
return reader.ReadToEnd();
//or handle it like you want
}
}
}
}
}
I don't know if it is good to keep all connection alive like that, but since it helped me to read actual responses from server, i think it might help someone, who faced the same problem.
EDIT: Also it is important not to mess with HttpWebRequest.DefaultMaximumErrorResponseLength.
I remember facing similar issue before and there was something related to setting the stream's position. Here is one of my solutions for reading webResponse that worked for me earlier. Please try if similar approach works for you:-
private ResourceResponse readWebResponse(HttpWebRequest webreq)
{
HttpWebRequest.DefaultMaximumErrorResponseLength = 1048576;
HttpWebResponse webresp = null;// = webreq.GetResponse() as HttpWebResponse;
var memStream = new MemoryStream();
Stream webStream;
try
{
webresp = (HttpWebResponse)webreq.GetResponse();
webStream = webresp.GetResponseStream();
byte[] readBuffer = new byte[4096];
int bytesRead;
while ((bytesRead = webStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
memStream.Write(readBuffer, 0, bytesRead);
}
catch (WebException e)
{
var r = e.Response as HttpWebResponse;
webStream = r.GetResponseStream();
memStream = Read(webStream);
var wrongLength = memStream.Length;
}
memStream.Position = 0;
StreamReader sr = new StreamReader(memStream);
string webStreamContent = sr.ReadToEnd();
byte[] responseBuffer = Encoding.UTF8.GetBytes(webStreamContent);
//......
//.......
Hope this helps!
Related
I am trying to make a very simple WinForms application with JWT authorization. It takes the inputted values for video games from the user and, using POST, inserts it into my API that's connected to SQL. However, I keep getting the bad request error even though I went over the code numerous times. I tested the exact same POST request on Postman and it works just fine there.
private void btnPost_Click(object sender, EventArgs e)
{
VideoGame videoGame = new VideoGame(
tbName.Text,
tbGenres.Text,
tbPlatforms.Text,
tbPublisher.Text,
tbDeveloper.Text,
dtpReleaseDate.Value,
tbDesc.Text,
nudPriceInEuro.Value);
DataContractSerializer serialization = new DataContractSerializer(typeof(VideoGame));
MemoryStream mStream = new MemoryStream();
XmlWriter writer = XmlWriter.Create(mStream);
serialization.WriteObject(writer, videoGame);
writer.Close();
byte[] serviceData = Encoding.UTF8.GetBytes(Encoding.UTF8.GetString(mStream.ToArray()));
string key = *my key goes here*;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://localhost:5000/api/VideoGames");
zahtjev.PreAuthenticate = true;
zahtjev.Headers.Add("Authorization", key);
zahtjev.Method = "POST";
zahtjev.Accept = "application/xml";
zahtjev.ContentType = "application/xml";
Stream data = request.GetRequestStream();
data.Write(serviceData, 0, serviceData.Length);
data.Close();
try
{
HttpWebResponse answer = (HttpWebResponse)request.GetResponse();
Stream answerData = answer.GetResponseStream();
DataContractSerializer deserialization = new DataContractSerializer(typeof(bool));
bool successAdded = (bool)deserialization.ReadObject(answerData);
if (successAdded)
{
lblSuccess.Text = "Success!";
}
else
{
lblSuccess.Text = "Unsuccessful!";
}
}
catch (WebException ex)
{
using (var stream = ex.Response.GetResponseStream())
using (var reader = new StreamReader(stream))
{
Console.WriteLine(reader.ReadToEnd());
}
}
}
I've got a web service that returns an http 500 with some diagnostic information in the body of the response.
I'm doing something like
Stream responseStream = null;
WebResponse _Response = null;
Stream responseStream = null;
HttpWebRequest _Request = null;
try
{
_Response = _Request.GetResponse();
responseStream = _Response.GetResponseStream();
}
catch {
//try to view the Request.GetResponse() body here.
}
Since _Request.GetResponse() is returning an http 500 there doesn't seem to be a way to view the response body. According to HTTP 500 Response with Body? this was a known issue in Java 9 years ago. I'm wondering if there's a way to do it in .NET today.
The microsoft docs give a good run down of what HttpWebRequest.GetResponse returns if it fails, you can check it out here https://learn.microsoft.com/en-us/dotnet/api/system.net.httpwebrequest.getresponse?view=netframework-4.8
In your example I believe you need to check for WebException and handle it.
Stream responseStream = null;
WebResponse _Response = null;
Stream responseStream = null;
HttpWebRequest _Request = null;
try
{
_Response = _Request.GetResponse();
responseStream = _Response.GetResponseStream();
}
catch (WebException w)
{
//here you can check the reason for the web exception
WebResponse res = w.Response;
using (Stream s = res.GetResponseStream())
{
StreamReader r= new StreamReader(s);
string exceptionMessage = r.ReadToEnd(); //here is your error info
}
}
catch {
//any other exception
}
I'm trying to send data to a server with this function :
public static async Task<Byte[]> sendData(Byte[] bt)
{
try
{
System.Net.HttpWebRequest myWebRequest = (HttpWebRequest)System.Net.HttpWebRequest.Create(URL);
myWebRequest.Method = "POST";
myWebRequest.ContentType = "text/xml";
myWebRequest.AllowReadStreamBuffering = true;
using (var requestStream = (Stream)(await Task<Stream>.Factory.FromAsync(myWebRequest.BeginGetRequestStream, myWebRequest.EndGetRequestStream, myWebRequest)))
{
requestStream.Write(bt, 0, bt.Length);
}
using (var response = (HttpWebResponse)(await Task<WebResponse>.Factory.FromAsync(myWebRequest.BeginGetResponse, myWebRequest.EndGetResponse, myWebRequest)))
{
using (var responseStream = response.GetResponseStream())
{
bt = new byte[responseStream.Length];
responseStream.Read(bt, 0, bt.Length);
return bt;
}
}
}
catch (Exception ex)
{
return null;
}
}
I get a response from the server saying that no data was sent (ContentLength == 0). Indeed, if I look at myWebRequest.ContentLength after writing in the stream request, _ContentLength is set to 0 and ContentLengthis set to -1.
Did I miss something ?
Thanks for your help !
try
{
FtpWebRequest req = (FtpWebRequest)WebRequest.Create("ftp path");
req.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
using (var resp = (FtpWebResponse)req.GetResponse())
{
Console.WriteLine(resp.WelcomeMessage);
}
FtpWebResponse res = (FtpWebResponse)req.GetResponse();
Stream rs = res.GetResponseStream();
StreamReader read1 = new StreamReader(res.GetResponseStream());// prob A
Console.WriteLine(read1.ReadToEnd());
Console.WriteLine("Directory is compleate,status(0)",
res.StatusDescription);
read1.Close();
rs.Close();
}
catch (Exception e1)
{
Console.WriteLine(e1.Message);
}
I am trying to access ftp server via C#.
However, the code errors with an exception:
A first chance exception of type "System.ArgumentException" occured in mscorlib.dll. Stream was not readable.
Any help will be appreciated.
Put all IDisposable resources within using(...) {...}. That technics prevents
resource leaking/closed resources invoking:
try {
FtpWebRequest req = (FtpWebRequest)WebRequest.Create("ftp path");
req.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
// Response: we're going to work wuth respose within "using" block only
using (FtpWebResponse resp = (FtpWebResponse)req.GetResponse()) {
Console.WriteLine(resp.WelcomeMessage);
// Reader: once again reader's opened once and called within using only
using (StreamReader reader = new StreamReader(resp.GetResponseStream())) {
Console.WriteLine(reader.ReadToEnd());
Console.WriteLine("Directory is complete, status(0)", resp.StatusDescription);
}
}
catch (Exception ex) { // <- Bad idea to catch all possible exceptions without "throw;"
Console.WriteLine(ex.Message);
}
TLDR; The state of the FtpWebResponse object is disposed, therefore you cannot read the response stream. The stream is closed.
Disassembly of FtpWebResponse:
public override void Close()
{
if (Logging.On)
{
Logging.Enter(Logging.Web, this, "Close", "");
}
if (this.HttpProxyMode)
{
this.m_HttpWebResponse.Close();
}
else
{
Stream responseStream = this.m_ResponseStream;
if (responseStream != null)
{
responseStream.Close();
}
}
if (Logging.On)
{
Logging.Exit(Logging.Web, this, "Close", "");
}
}
The reason you get the exception, is that you are reading the response:
using (var resp = (FtpWebResponse)req.GetResponse())
{
Console.WriteLine(resp.WelcomeMessage);
}
and on the next line, you try to read the response again, into another variable: res
FtpWebResponse res = (FtpWebResponse)req.GetResponse();
Stream rs = res.GetResponseStream();
StreamReader read1 = new StreamReader(res.GetResponseStream());// prob A
In that section, you also do a call to the res.GetResponseStream() twice, but that does not matter in terms of the error occuring. The error will occur even if you change it to:
FtpWebResponse res = (FtpWebResponse)req.GetResponse();
Stream rs = res.GetResponseStream();
StreamReader read1 = new StreamReader(rs);// prob A
Or:
FtpWebResponse res = (FtpWebResponse)req.GetResponse();
StreamReader read1 = new StreamReader(res.GetResponseStream());// prob A
The reason that the error occurs, is the state of the FtpWebResponse object, which is disposed; and has the StatusCode = ClosingData. When I try to read the stream in that state, I get the error you are experiencing. In the using block before, the StatusCode = OpeningData.
However, if you just change a couple of lines to:
using (var resp = (FtpWebResponse)req.GetResponse())
{
Console.WriteLine(resp.WelcomeMessage);
Stream rs = res.GetResponseStream();
StreamReader read1 = new StreamReader(rs);// prob A
Console.WriteLine(read1.ReadToEnd());
Console.WriteLine("Directory is compleate,status(0)", res.StatusDescription);
}
When entering this using scope, the StatusCode = OpeningData, and stream is available and readable. When exiting the scope, the StatusCode = ClosingData, and stream will not be readable.
Hope this make some sense, and correct me if I'm wrong. :-)
With these small changes your code will run as expected. However you should look into the pattern #DmitryBychenko proposes. That way you will have access to the resources within the scope that they're needed, and disposed afterwards.
After I make two C# HttpWebRequests that throw an exception because of "(500) Internal Server Error 500", the third attempt throws a time out exception. Why doesn't it throw another (500) Internal Server Error exception?
When I restart my application, it throws two 500 errors and then starts timing out again.
This is my code:
GetPages GetPages = new GetPages();
string test = GetPages.GetPage(); /* Exception: (500) Internal Server Error */
GetPages.Dispose();
GetPages GetPages = new GetPages();
string test = GetPages.GetPage(); /* Exception: (500) Internal Server Error */
GetPages.Dispose();
GetPages GetPages = new GetPages();
string test = GetPages.GetPage(); /* Exception: time out, why? */
GetPages.Dispose();
This is GetPages class and GetPage method:
namespace MyNamespace
{
class GetPages
{
public string GetPage()
{
this.httpRequest = (HttpWebRequest)WebRequest.Create("http://myurl");
try
{
StringBuilder postData = new StringBuilder(100);
postData.Append("test=test");
byte[] dataArray = Encoding.UTF8.GetBytes(postData.ToString());
httpRequest.CachePolicy = new HttpRequestCachePolicy(HttpRequestCacheLevel.NoCacheNoStore);
httpRequest.KeepAlive = false;
httpRequest.Proxy = null;
httpRequest.Method = "POST";
httpRequest.Timeout = 10;
httpRequest.ContentType = "application/x-www-form-urlencoded";
httpRequest.ContentLength = dataArray.Length;
using (this.requestStream = httpRequest.GetRequestStream())
{
requestStream.Write(dataArray, 0, dataArray.Length);
requestStream.Flush();
requestStream.Close();
this.webResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream responseStream = webResponse.GetResponseStream();
StreamReader responseReader = new System.IO.StreamReader(responseStream, Encoding.UTF8);
String responseString = responseReader.ReadToEnd();
MessageBox.Show(responseString);
return responseString;
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
return "FAIL";
}
}
public void Dispose()
{
System.GC.SuppressFinalize(this);
}
}
}
UPDATE
Thanks you all for helping out. I have not been able to solve the issue.
The dispose method is gone now.
I have made HttpWebRequest httpRequest, HttpWebResponse webResponse and Stream requestStream local and am using the following using statements:
using (webResponse = (HttpWebResponse)httpRequest.GetResponse())
{
using (Stream responseStream = webResponse.GetResponseStream())
{
using (StreamReader responseReader = new System.IO.StreamReader(responseStream, Encoding.UTF8))
{
responseString = responseReader.ReadToEnd();
}
}
}
Another update
This is the entire GetPage method now:
public string GetPage()
{
HttpWebRequest httpRequest;
HttpWebResponse webResponse;
Stream requestStream;
try
{
StringBuilder postData = new StringBuilder(100);
postData.Append("test=test");
byte[] dataArray = Encoding.UTF8.GetBytes(postData.ToString());
httpRequest = (HttpWebRequest)WebRequest.Create("http://myurl");
httpRequest.Proxy = null;
httpRequest.Method = "POST";
httpRequest.Timeout = 10;
httpRequest.ContentType = "application/x-www-form-urlencoded";
httpRequest.ContentLength = dataArray.Length;
using (requestStream = httpRequest.GetRequestStream())
{
/* this is never reached when the time out exception starts
so the error seems to be related to too many GetRequestStreams */
requestStream.Write(dataArray, 0, dataArray.Length);
webResponse = (HttpWebResponse)httpRequest.GetResponse();
/* this is never reached when the 500 server error occurs */
String responseString = "";
using (Stream responseStream = webResponse.GetResponseStream())
{
using (StreamReader responseReader = new System.IO.StreamReader(responseStream, Encoding.UTF8))
{
responseString = responseReader.ReadToEnd();
return responseString;
}
}
}
}
catch (Exception e)
{
return "FAIL";
}
return "...";
}
** SOLVED!! **
httpRequest was not getting abort()'ed. In the catch() block I have added httpRequest.abort(), now it works correctly.
I suspect this is the problem:
this.webResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream responseStream = webResponse.GetResponseStream();
StreamReader responseReader = new StreamReader(responseStream, Encoding.UTF8);
String responseString = responseReader.ReadToEnd();
You're not disposing of any of these disposable objects. That means the connection to the web server will be maintained until finalization, so the connection pool (of two connections per server) won't allow any other requests.
I suggest that:
You move the GetResponse call out of the using statement for the request stream
You remove the explicit calls to Flush and Close for the request stream (disposing of it is good enough)
You make webResponse and webRequest local variables instead of instance variables unless you really need them later, in which case you should dispose of them in your Dispose method.
You use using statements for the WebResponse, Stream, and StreamReader. (The last isn't strictly necessary, as disposing of the stream is good enough.)
You make GetPages not implement IDisposable unless you really need it to.
HTTP protocol defines that only two connection can be made at the same time to the same server. Close the responseStream after successful or unsuccessful reading.