ManualResetEvent.set not getting fired in C# - c#

I am working on Visual Web Express 2010.
I am trying to upload a file to server and block the calling function and release it once uploading is complete. However, the main thread never gets unblocked.
public partial class MainPage : UserControl
{
private FileStream fileStream;
private static String responseStr = "";
private static ManualResetEvent evt = new ManualResetEvent(false);
public MainPage()
{
InitializeComponent();
HtmlPage.RegisterScriptableObject("App", this);
}
public void sendPhoto()
{
uploadFile();
}
private void uploadFile()
{
uploadDataToServer(url);
evt.WaitOne();
postProcess();
}
public static void postProcess()
{
HtmlPage.Window.Invoke("postProcess2", responseStr);
}
void uploadDataToServer(String url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.ContentType = "multipart/form-data; boundary=---------------------------" + _boundaryNo;
request.Method = "POST";
request.BeginGetRequestStream(writeCallback, request);
}
private void writeCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
MemoryStream memoryStream = new MemoryStream();
fileStream.CopyTo(memoryStream);
if (memoryStream != null)
{
memoryStream.Position = 0;
byte[] img = memoryStream.ToArray();
Stream postStream = request.EndGetRequestStream(asynchronousResult);
postStream.Write(img, 0, img.Length);
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
streamRead.Close();
streamResponse.Close();
response.Close();
responseStr = responseString;
evt.Set();
}
}
Now, when I use evt.WaitOne() in uploadFile, the whole app goes waiting and no request is send to server, i.e. the code never reaches getResponseCallBack and hence the application never wakes up.
However, if I don't use evt.WaitOne(), then the request is successful, however I can't read the response text since it's set in writeCallBack() function and the request is async one. What should I do to get over this problem?
I can't figure out:
1. If the request is multi-threaded / Async, then why evt.WaitOne() makes the complete app waiting and the request doesn't complete?
2. If the request is single threaded, then why postProcess() [removing the evt.WaitOne()] on trying to access responseStr [set in the getResponseCallBack()] doesn't get the proper response set in it.
[Sorry, I am new to this and am confused].
Thanks.
Sorry, I forgot to mention one thing that, I am using silverlight.

There is no point in starting an async operation and then waiting for it to complete. Instead of async request.BeginGetRequestStream(writeCallback, request); use the synchronous request.GetRequestStream(...) and consume it's result. ManualResetEvent would not be needed then.

Here is the solution to the problem that I figured out:
Some have advised to use HttpWebRequest.GetRequestStream and make the call synchronous. However, as it seems that silverlight doesn't allow this to take place. Moreover, there was many confusion related to threading and parrallel-processing.
The main problem was that I wasn't able to access the UI thread from my callback function, so I used the dispatcher method and since it always makes sure that the actions are performed in UI thread, my objective got fulfilled. The following did the trick.
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() => { postProcess(); });

Related

Continuously Consuming API in winform (C#)

I've made a simple program that has to continuosly check for data based on API.
So far, what I've done is making a timer, then execute the GET procedures on timer event
private void TimerStatus_Tick(object sender, EventArgs e)
{
//stop timer
TimerStatus.Stop();
//get data
getCommand();
//restart timer
TimerStatus.Start();
}
void getCommand()
{
string url = "https://somewhere/getcommand?token=somekey&param=";
string param = "0";
WebRequest request = WebRequest.Create(url + param ); ;
request.Method = "GET";
request.ContentType = "application/x-www-form-urlencoded";
request.Credentials = CredentialCache.DefaultCredentials;
try
{
WebResponse response = request.GetResponse();
bool connected = false;
if ((((HttpWebResponse)response).StatusDescription) == "OK")
connected = true;
//continue if connected
if (connected)
{
using (Stream dataStream = response.GetResponseStream())
{
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader(dataStream);
// Read the content.
string responseFromServer = reader.ReadToEnd();
//check output
Console.WriteLine("Respond from server : " + responseFromServer);
try
{
//parse data, store value
parseThenProcess(responseFromServer);
}
catch
{
//parsing data error
Console.WriteLine("exception error response");
}
}
}
// Close the response.
response.Close();
}
catch
{
Console.WriteLine("Get command failed");
}
}
This code works fine for me. However, when I try to add more command that has different API in the timer event, the winforms feels kinda laggy. Is it just error on my side that irrelevant with the API handling or do I need to make some improvement about how to handle the API?
private void TimerStatus_Tick(object sender, EventArgs e)
{
//stop timer
TimerStatus.Stop();
//get data
getCommand_A();
getCommand_B();
getParameter_C();
getParameter_D();
//restart timer
TimerStatus.Start();
}
Not using a windows timer? And I am not joking. You have various approaches:
Learn how to use async and the async web interfaces so you do not block the UI thread too long.
or
use a separate thread or tasks (no need for a timer , you can have a task that then schedules another task, i.e.).
What you do is running it all on the UI thread and that is really not needed. Especially because you do send that synchronous so the UI blocks while the request is executed .This is a problem solved for many years by the UI knowing of async methods.

How to wait in WinForms application for X seconds without the UI freezing?

I have this code, but the API has limited requests per minute, so I sometimes get error 429.
I need to wait about a minute, but the WinForm UI becomes unresponsive (I guess I'm stopping thread with UI doing this?). What would be the proper way to implement this?
Code:
public static int sleepTime { get; set; } = 60000;
public static string GetData(string URL)
{
while (true) {
try
{
Controller.SetAppStatus(AppStatusses.FetchingData);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string rt = reader.ReadToEnd();
return rt;
}
catch
{
Controller.SetAppStatus(AppStatusses.Timeout);
Timeout();
}
}
}
public static async void Timeout() {
await Task.Delay(sleepTime);
}
Use HttpClient class : ms docs, its the recommended way of issuing requests and it has async methods so you can make your logic asynchronous and you won't block the UI thread. In addition, you have to await the Timeout method and return a Task from it so no blocking would happen.

HttpWebResponse ReadAsync time out

I try to read stream of HttpWebResponse using await/async:
async static Task testHttpWebClientAsync()
{
string url = "http://localhost/1.txt";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "GET";
HttpWebResponse resp = (HttpWebResponse)await req.GetResponseAsync();
Stream stream = resp.GetResponseStream();
stream.ReadTimeout = 10 * 1000;
byte[] buffer = new byte[1024];
while (await stream.ReadAsync(buffer, 0, buffer.Length) > 0)
{
//time out exception never thrown
}
}
But it doesn't work, it never time out on ReadAsync.
For comparison a non-async version work perfectly with the same localhost test server:
static void testHttpWebClient()
{
string url = "http://localhost/1.txt";
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "GET";
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
Stream stream = resp.GetResponseStream();
stream.ReadTimeout = 10 * 1000;
byte[] buffer = new byte[1024];
while (stream.Read(buffer, 0, buffer.Length) > 0)
{
//time out exception thrown here
}
}
The above code is tested in a console application:
static void Main(string[] args)
{
testHttpWebClient();
MainAsync(args).GetAwaiter().GetResult();
}
async static Task MainAsync(string[] args)
{
await testHttpWebClientAsync();
}
But this is not relevant to the problem, indeed I find the problem in a WinForms project and create the console project to test the problem.
For reference, the test server code is something like:
int c = 10;
byte[] ba = new byte[1024];
SendHeader(sHttpVersion, sMimeType,(int) ba.Length*c, " 200 OK", ref mySocket);
for (int k = 0; k < c; k++)
{
//set break point here
SendToBrowser(ba, ref mySocket);
}
There are several similar topics on SO, but it seems that none of them solve this problem. From API design perspective, obviously there is no reason that ReadAsync() doesn't time out just like Read() does, ReadAsync only need to watch both the socket and an internal timer event, this is how Task.Delay() works. This has nothing to do with CancellationToken,etc because we don't need to cancel anything, even ReadAsync has a version that accept CancellationToken.
So this question is both for a solution for the problem, and why ReadAsync doesn't just time out as expected.
Asynchronous APIs on HttpWebRequest (and on WebClient since it uses HttpWebRequest internally) do not use timeouts internally. While I can't really explain the reasoning behind it, this is by design.
This is especially apparent in the Write logic of the ConnectStream (used internally by HttpWebResponse):
if (async) {
m_Connection.BeginMultipleWrite(buffers, m_WriteCallbackDelegate, asyncResult);
}
else {
SafeSetSocketTimeout(SocketShutdown.Send);
m_Connection.MultipleWrite(buffers);
}
SafeSetSocketTimeout is the method responsible of setting the timeout on the underlying socket. As you can see, it's deliberately skipped on the async path. It's the same thing for read operations, but the code is more convoluted so it's harder to show.
Therefore, you really have only two solutions:
Implement the timeout yourself (usually with a timer that calls .Abort() on the HttpWebRequest)
Use HttpClient instead

HttpListener Called twice

I am using this code to implement Http Server:
public Server()
{
_httpListener = new HttpListener();
_httpListener.Prefixes.Add(Server.UriAddress);
StartServer();
}
public void StartServer()
{
_httpListener.Start();
while (_httpListener.IsListening)
ProcessRequest();
}
void ProcessRequest()
{
var result = _httpListener.BeginGetContext(ListenerCallback, _httpListener);
result.AsyncWaitHandle.WaitOne();
}
void ListenerCallback(IAsyncResult result)
{
HttpListenerContext context = _httpListener.EndGetContext(result);
HttpListenerRequest request = context.Request;
string url = request.RawUrl;
url = url.Substring(1, url.Length - 1);
HttpListenerResponse response = context.Response;
string responseString = url;
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
System.IO.Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
}
And i have a problem that if i wrote this in the browser(It's an example and it's occur on every call):
http://localhost:8888/Hello%20World
the ListenerCallback method is called twice,any idea how to fix it?
An answer has been accepted already, but I think it may still be useful to other people subsequently.
By default, most browsers given a URL would make at least two calls. One call to the request URL and the other to favicon.ico.
So a check should be made in ListenerCallback like
HttpListenerContext context = _httpListener.EndGetContext(result);
HttpListenerRequest request = context.Request;
string url = request.RawUrl;
url = url.Substring(1);
if (url == "favicon.ico")
{
return;
}
//normal request handling code
I hope this helps someone.
If your website requires several calls to the server, it will be called several times. This happens when you hav pictures or anything else on you page.
Try to call the synchronous method _httpListener.GetContext() or synchronize your calls with a lock or Mutex.
I am not sure but I think I see what might be a problem with your code.
You are mixing two patterns of async handling
You release the main thread by waiting on the waithandle in the async result.
But I think that only signals that you can call endgetcontext, not that another thread can use the listener.
If you are using the callback pattern, you should release the main thread using a wait handle other than that provided in the asyncresult

Problem to pass the result to the caller for asynchronous httpWebRequest

In Silverlight I want to be able to get the output from a Helper class like this:
public MainPage()
{
InitializeComponent();
String ouput;
Helper helper = new Helper(url);
Helper.invoke(output);
}
I can't see how to do that since in Helper Class I am obliged to do an asynchronous call:
private String webserviceUrl;
private XDocument xdoc = new XDocument();
public Helper(String webserviceUrl)
{
this.webserviceUrl = webserviceUrl;
}
public void invoke(ref String output)
{
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(this.webserviceUrl);
try
{
HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.BeginGetResponse(new AsyncCallback(HandlerWebResponse), httpWebResponse);
}
catch
{
}
}
private void HandlerWebResponse(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
using (StreamReader streamReader1 = new StreamReader(response.GetResponseStream()))
{
string resultString = streamReader1.ReadToEnd();
}
}
It looks like you're basically trying to get away from the asynchronous model. While you can do that by effectively blocking until the event handler for the asynchronous request has fired, you really shouldn't. There are good reasons for Silverlight to only support asynchronous web operations - you should go with that decision.
It's fine to have a helper class to effectively perform a transformation on the result, but I'd suggest doing that in an asynchronous style - pass in an event handler which will be called when the request completes (either successfully or unsuccessfully). Transform the result (e.g. reading it as a string) and then call the event handler.
It can be a bit of a pain, admittedly, but you really need to start thinking in terms of an asynchronous model.
You might also want to look at WebClient which already has support for fetching an HTTP result as a string.
Create an event to notify that the service has been successfully consumed. In the event parameters you can pass the result of the invoked web services.
public event Action<string> ResponseResult;
You can then invoke this event in your web response handler:
private void HandlerWebResponse(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
using (StreamReader streamReader1 = new StreamReader(response.GetResponseStream()))
{
string resultString = streamReader1.ReadToEnd();
if (ResponseResult != null)
ResponseResult(resultString);
}
}
And in your code the initiates the service call you can subscribe to this event to get notified when it has finished:
Helper helper = new Helper(url);
public MainPage()
{
InitializeComponent();
Helper.ResponseResult += ResponseHandler;
Helper.invoke(output);
}
public void ResponseHandler(string response)
{
// do something with response
}

Categories