I'm trying to write a tool in C# to help QA some network issues, and am running into a problem. The program is supposed to send a query in JSON format to the server every second.
Currently, it works once, but on the second attempt to send the query, I get an exception because the
"Stream was not writable."
Here's my code:
public partial class Form1 : Form
{
Timer timer1;
String query;
String result;
HttpWebRequest request;
StreamWriter writeData;
StreamReader readData;
HttpWebResponse response;
public Form1()
{
InitializeComponent();
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 1000;
File.Delete(AppDomain.CurrentDomain.BaseDirectory + "log.txt");
logOutput.ReadOnly = true;
request = (HttpWebRequest)WebRequest.Create("a URL goes here");
request.ContentType = "application/json";
request.Method = "POST";
query = "{some json stuff goes here}";
}
private void startButton_Click(object sender, EventArgs e)
{
if (!timer1.Enabled)
{
timer1.Start();
startButton.Text = "Stop";
}
else
{
timer1.Stop();
startButton.Text = "Start";
}
}
private void timer1_Tick(object sender, EventArgs e)
{
writeData = new StreamWriter(request.GetRequestStream());
writeData.Write(query);
writeData.Flush();
writeData.Close();
response = (HttpWebResponse)request.GetResponse();
readData = new StreamReader(response.GetResponseStream());
result = readData.ReadToEnd();
logOutput.Text = result;
File.AppendAllText(AppDomain.CurrentDomain.BaseDirectory + "log.txt", result + "\r\n");
}
}
}
Anyone know what I'm doing wrong?
First off, Stop with the global variables. Move the streamwriter, streamreader, httpwebresponse etc into the actual tick method.
Anything that implements IDisposable, which most of that stuff does, should be very local variables that aren't hanging around and are wrapped up in using clauses.
Basically your request object is closed out once your method has finished.
Something like this will work a LOT better:
private void timer1_Tick( object sender, EventArgs e ) {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("a URL goes here");
request.ContentType = "application/json";
request.Method = "POST";
String query = "{some json stuff goes here}";
String result = String.Empty;
using ( StreamWriter writeData = new StreamWriter(request.GetRequestStream()) ) {
writeData.Write(query);
writeData.Flush();
using ( HttpWebResponse response = (HttpWebResponse)request.GetResponse() ) {
using ( StreamReader readData = new StreamReader(response.GetResponseStream()) ) {
result = readData.ReadToEnd();
}
}
}
logOutput.Text = result;
File.AppendAllText(AppDomain.CurrentDomain.BaseDirectory + "log.txt", result + "\r\n");
}
}
So I presume it's the writeData.Write(query) that's throwing? request.GetRequestStream() should only be writeable until the request is actually sent, which I believe is done when you call request.GetResponse(). So it works on the first tick, but then sends the request and can't write the second time.
Are you trying to send the request multiple times? You would need to reinitialize the request object.
Similar issue causes if you do not reinitialize the request. As mentioned by ryachza i have pushed request initialization inside loop and it worked for me.
foreach (String item in DATA)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "application/json";
using (Stream webStream = request.GetRequestStream())
using (StreamWriter requestWriter = new StreamWriter(webStream, System.Text.Encoding.ASCII))
{
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
Object routes_list =
json_serializer.DeserializeObject(item);
requestWriter.Write(item);
}
WebResponse webResponse = request.GetResponse();
using (Stream webStream = webResponse.GetResponseStream() ?? Stream.Null)
using (StreamReader responseReader = new StreamReader(webStream))
{
response.Add(responseReader.ReadToEnd());
}
}
Related
In my C# application I have a while loop that gathers a string from a Redis message queue and sends it to a listening server.
At every cicle the connection is opened with an HttpWebRequest Post method and the data is sent using a StreamWriter variable.
Problem is: after sending two strings the application freezes without returning any error, it just does nothing for maybe a minute, after that it works again correctly and continues its job for another couple strings, freeze and so on.
Debug shows the delay happens during the declaration of the StreamWriter variable.
Here is the core of the code:
// configure Redis
var redis = new RedisClient("127.0.0.1");
while (true)
{
// read from Redis queue
string json = redis.BRPop(30, "sensors_data");
//...
//URL DECLARATION
//...
try
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentLength = json.Length;
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
httpWebRequest.Proxy = null;
SendDataAsync(json, url);
}
}
static async Task SendDataAsync(string json, string url)
{
try
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentLength = json.Length;
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
httpWebRequest.Proxy = null;
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
try
{
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
Console.Write("Data Sent");
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
catch (Exception err)
{
Console.Write(err.Message);
}
Console.WriteLine();
}
So the code actually works, just there is some strange huge delay where it comes to declare the StreamWriter. Does anyone have any idea? I don't know how to handle the problem.
EDIT
while (true)
{
i = 0;
// read from Redis queue
string json = redis.BRPop(30, "sensors_data");
try
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentLength = json.Length;
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
httpWebRequest.Proxy = null;
using (StreamWriter streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
try
{
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
var response = httpWebRequest.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string reply=reader.ReadToEnd();
Console.WriteLine(reply);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
catch (Exception err)
{
Console.Write(err.Message);
}
Console.WriteLine();
}
Found the solution: Apparently it is necessary to get an answer from the server, after I added the httpWebRequest.GetResponse() and the following two lines I didn't find delays anymore.
Suggestion: it's better to use WebClient, it didn't give me any problem from the first try.
I am attempting to create a console app that sends a WebRequest to a website so that I can get some information back from it in JSON format. Once I build up the request and try to get response I just want to simply print out the data, but when I call httpWebRequest.getResponse() it returns NULL.
I have tried multiple other methods of sending the data to the the url but those are all giving me like 404, or 400 errors, etc. This method at least isn't giving me any error, just a NULL.
Here is a snapshot of the documentation I am using for the API (albeit the docs aren't complete yet):
Here is the console app code that I have right now:
try
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://api.remot3.it/apv/v27/user/login");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
httpWebRequest.Headers.Add("developerkey", "***KEY***");
using (var streamWriter = new
StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = new JavaScriptSerializer().Serialize(new
{
email = "***EMAIL***",
password = "***PASSWORD***"
});
Console.WriteLine(json);
streamWriter.Write(json);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
Console.WriteLine(result);
Console.ReadLine();
}
}catch(Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
Console.ReadLine();
}
Expected output is some JSON data, but I am getting a NULL back from getResponse().
Try to serialize the credential in your form and for header send as parameter for this class.
Check below for my code. It is not 100 % fit to your requirement, but atleast it will help to get through your logic.
Here is what I get Json Response from this code. Its work Perfect. Please remember to add timeout option on your webrequest and at the end close the streamreader and stream after completing your task. please check this code.
public static string httpPost(string url, string json)
{
string content = "";
byte[] bs;
if (json != null && json != string.Empty)
{
bs = Encoding.UTF8.GetBytes(json);
}
else
{
bs = Encoding.UTF8.GetBytes(url);
}
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
req.Method = "POST";
if (json != string.Empty)
req.ContentType = "application/json";
else
req.ContentType = "application/x-www-form-urlencoded";
req.KeepAlive = false;
req.Timeout = 30000;
req.ReadWriteTimeout = 30000;
//req.UserAgent = "test.net";
req.Accept = "application/json";
req.ContentLength = bs.Length;
using (Stream reqStream = req.GetRequestStream())
{
reqStream.Write(bs, 0, bs.Length);
reqStream.Flush();
reqStream.Close();
}
using (WebResponse wr = req.GetResponse())
{
Stream s = wr.GetResponseStream();
StreamReader reader = new StreamReader(s, Encoding.UTF8);
content = reader.ReadToEnd();
wr.Close();
s.Close();
reader.Close();
}
return content;
}
I am able to send the first request working fine, however I can't get my head round why it stalls on getting the Stream os = smsRequest.GetRequestStream() the second time.
I am aware that you can't write to a Request more than once that is why a new instance is created each time.
public void SendSMS(Dictionary<double, IList<string>> texts)
{
if (CreateWebRequest())
{
foreach (double mpn in texts.Keys)
{
foreach (string sms in texts[mpn])
{
string formParams = string.Format("sendTo=0{0}&selectText=Please+Select...&textMessage={1}&x=28&y=10", mpn, sms);
byte[] encodedParams = Encoding.UTF8.GetBytes(formParams);
HttpWebRequest smsRequest = CreateSMSRequest(encodedParams);
using (Stream os = smsRequest.GetRequestStream())
{
os.Write(encodedParams, 0, encodedParams.Length);
os.Close();
}
}
}
}
}
private HttpWebRequest CreateSMSRequest(byte[] encodedParams)
{
HttpWebRequest smsRequest = (HttpWebRequest)WebRequest.Create(PostUrl);
smsRequest.Method = WebRequestMethods.Http.Post;
smsRequest.ContentType = "application/x-www-form-urlencoded";
smsRequest.ContentLength = encodedParams.Length;
smsRequest.AllowAutoRedirect = false;
smsRequest.Credentials = CredentialCache.DefaultNetworkCredentials;
smsRequest.Headers.Add(HttpRequestHeader.Cookie, _cookieData);
return smsRequest;
}
I think your answer is the same as this one:
HttpWebRequest getRequestStream hangs on multiple runs
After your using statement put:
var response = smsRequest.GetResponse() as HttpWebResponse;
Here's my code:
namespace RequestApi
{
public partial class MainPage : PhoneApplicationPage
{
private BackgroundWorker bw;
private string ans;
private JObject ansJson;
private static ManualResetEvent allDone = new ManualResetEvent(false);
// Constructor
public MainPage()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
string url = "http://192.168.0.43:8182/Account/SignIn";
CreateRequest(url);
userId.Text = ansJson.Value<int>("user_id").ToString();
}
private void CreateRequest(string url)
{
Debug.WriteLine("CreateRequest");
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(url);
req.ContentType = "application/json";
req.Method = "POST";
req.BeginGetRequestStream(new AsyncCallback(RequestCallback), req);
allDone.WaitOne();
}
private void RequestCallback(IAsyncResult aresult)
{
Debug.WriteLine("RequestCallback");
HttpWebRequest req = (HttpWebRequest)aresult.AsyncState;
Stream postStream = req.EndGetRequestStream(aresult);
string obj = "{ 'username': 'test_2#aragast.com', 'password': 'a123456' }";
JObject json = JObject.Parse(obj);
string s = JsonConvert.SerializeObject(json);
byte[] postdata = System.Text.Encoding.Unicode.GetBytes(s);
postStream.Write(postdata, 0, postdata.Length);
postStream.Close();
req.BeginGetResponse(new AsyncCallback(ResponseCallback), req);
}
private void ResponseCallback(IAsyncResult aresult)
{
Debug.WriteLine("ResponseCallback");
HttpWebRequest req = (HttpWebRequest)aresult.AsyncState;
HttpWebResponse resp = (HttpWebResponse)req.EndGetResponse(aresult);
StreamReader reader = new StreamReader(resp.GetResponseStream());
string response = reader.ReadToEnd();
Debug.WriteLine(response);
JObject responseJson = JObject.Parse(response);
ansJson = responseJson;
Debug.WriteLine("ansJson from responseCallback {0}", ansJson);
reader.Close();
resp.Close();
allDone.Set();
}
}
}
When I debug application it entered CreateRequest then it enter RequestCallback, but then it stop and never enter ResponseCallback instead it tryis userId.Text to assign asnJson value which is null, because it doesn't enter ResponseCallback. When I do wrong, and why it never enter ResponseCallback?
Your ManualResetEvent is created with true as the argument, so it's already signalled to start with. That means the allDone.Wait() call will immediately continue... so CreateRequest will finish, and you'll immediately try to use the asnJson variable, which as you've said is null. That will kill the application, I suspect - so you never get a chance to get a response.
Now, the solution to this is not to change the ManualResetEvent constructor - you shouldn't be waiting like that in the UI thread anyway! You'll block it, and you've removed the whole point of Windows Phone 7 making everything asynchronous to start with.
Instead, your callbacks should use the dispatcher to call back into the UI thread when they've finished. Note that you should also have robust error handling in case anything goes wrong with the request.
Not exactly related to answering the question, but an answer block seems to be the only place to fit the recommendation I'm about to make... You should have appropriate resource protection around your streams by employing using blocks as such:
Original code:
Stream postStream = req.EndGetRequestStream(aresult);
string obj = "{ 'username': 'test_2#aragast.com', 'password': 'a123456' }";
JObject json = JObject.Parse(obj);
string s = JsonConvert.SerializeObject(json);
byte[] postdata = System.Text.Encoding.Unicode.GetBytes(s);
postStream.Write(postdata, 0, postdata.Length);
postStream.Close();
New code (also make sure your encoding is correct for the request: is your web service really expecting UTF-16? It's more common that web servers use UTF-8 (Encoding.UTF8)) :
using (Stream postStream = req.EndGetRequestStream(aresult))
{
string obj = "{ 'username': 'test_2#aragast.com', 'password': 'a123456' }";
JObject json = JObject.Parse(obj);
string s = JsonConvert.SerializeObject(json);
byte[] postdata = System.Text.Encoding.Unicode.GetBytes(s);
postStream.Write(postdata, 0, postdata.Length);
}
Original code:
HttpWebResponse resp = (HttpWebResponse)req.EndGetResponse(aresult);
StreamReader reader = new StreamReader(resp.GetResponseStream());
string response = reader.ReadToEnd();
Debug.WriteLine(response);
JObject responseJson = JObject.Parse(response);
ansJson = responseJson;
Debug.WriteLine("ansJson from responseCallback {0}", ansJson);
reader.Close();
resp.Close();
New code:
using (HttpWebResponse resp = (HttpWebResponse)req.EndGetResponse(aresult))
using (StreamReader reader = new StreamReader(resp.GetResponseStream()))
{
string response = reader.ReadToEnd();
Debug.WriteLine(response);
JObject responseJson = JObject.Parse(response);
ansJson = responseJson;
Debug.WriteLine("ansJson from responseCallback {0}", ansJson);
}
I would also recommend surrounding your req and resp operations with try..catch blocks to allow something to process exceptional conditions -- otherwise it will bubble up to the AppDomain's exception handler (can also be hooked by the UnhandledException event).
I'm trying to get the picture to load in the same PHP session in which the POST request will be sent.
But because i'm using button1_Click this is not possible.
And the outcome is to get the picture to load before the data is sent.
If you got any questions please ask.
i know i go wrong with the picture loading, but i dont know exactly where..
using visual c# 2010 express winforms
private void Form1_Load(object sender, EventArgs e)
{
pictureBox1.ImageLocation = "http://localhost/proj/guess-my-fav/1.jpg";
}
private void button1_Click(object sender, EventArgs e)
{
Uri uri = new Uri("http://localhost/proj/guess-my-fav/level14.php");
var answer = textBox1.Text;
string data = "guess=" + answer + "&level=14&time=opt";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Post;
request.CookieContainer = new CookieContainer();
request.KeepAlive = true;
request.ContentLength = data.Length;
request.ContentType = "application/x-www-form-urlencoded";
StreamWriter writer = new StreamWriter(request.GetRequestStream());
writer.Write(data);
writer.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string tmp = reader.ReadToEnd();
response.Close();
richTextBox1.AppendText(tmp); // log - delete this line
}
How can i put the rendering of image under the second request?
pictureBox1.ImageLocation = "http://localhost/proj/guess-my-fav/1.jpg";
This is going to cause the client's browser to make a request for 1.jpg
Uri uri = new Uri("http://localhost/proj/guess-my-fav/level14.php");
...
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
This is going to cause the webserver running the ASP.NET website to make a request for level14.php
You're not going to get those two requests using the same session since they'll be coming from two different machines!
You might like to look into moving that HttpWebRequest code out of the back end, and reimplementing it on the client side as an AJAX request. Then both requests will be coming from the client's browser.
If you modify your code to match
private CookieContainer cookieContainer;
private void Form1_Load(object sender, EventArgs e)
{
var wr = (HttpWebRequest)WebRequest.Create("http://localhost/proj/guess-my-fav/1.jpg");
cookieContainer = new CookieContainer();
wr.CookieContainer = this.cookieContainer;
var resp = (HttpWebResponse)wr.GetResponse();
wr.CookieContainer = cookieContainer;
using (var s = resp.GetResponseStream())
{
pictureBox1.Image = new Bitmap(s);
}
}
private void button1_Click(object sender, EventArgs e)
{
Uri uri = new Uri("http://localhost/proj/guess-my-fav/level14.php");
var answer = textBox1.Text;
string data = "guess=" + answer + "&level=14&time=opt";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Post;
request.CookieContainer = cookieContainer;
request.KeepAlive = true;
request.ContentLength = data.Length;
request.ContentType = "application/x-www-form-urlencoded";
StreamWriter writer = new StreamWriter(request.GetRequestStream());
writer.Write(data);
writer.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string tmp = reader.ReadToEnd();
response.Close();
richTextBox1.AppendText(tmp); // log - delete this line
}
This should make both requests to the server using the same session.
Hope this helps.
I am assuming here that you want to re-load the image when you click the button.
First of all that ImageLocation property is probably not gonna respect your session cookie, so you might have to download the image manually. You already used a CookieContainer so that's a good start.
What we want to do here is use a new HttpWebRequest to download the image and attach the same CookieContainer to it as this one should hold the session id after your first call.
We can then use the HttpWebResponse to create an Image object and assign this to the pictureBox1.Image property.
All this together might look something like this:
private void button1_Click(object sender, EventArgs e)
{
Uri uri = new Uri("http://localhost/proj/guess-my-fav/level14.php");
var answer = textBox1.Text;
string data = "guess=" + answer + "&level=14&time=opt";
CookieContainer cookies = new CookieContainer(); /* we want to have this for other call also
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Post;
request.CookieContainer = cookies;
request.KeepAlive = true;
request.ContentLength = data.Length;
request.ContentType = "application/x-www-form-urlencoded";
StreamWriter writer = new StreamWriter(request.GetRequestStream());
writer.Write(data);
writer.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string tmp = reader.ReadToEnd();
response.Close();
richTextBox1.AppendText(tmp); // log - delete this line
HttpWebRequest request2 = (HttpWebRequest)HttpWebRequest.Create("http://localhost/proj/guess-my-fav/1.jpg");
request2.CookieContainer = cookies;
HttpWebResponse response2 = (HttpWebResponse)request.GetResponse();
pictureBox1.Image = Image.LoadFromStream(response2.GetResponseStream());
}