WebRequest.BeginGetResponse does not work asynchronously - c#

I have C# code and have a problem with webRequest.begingetresponse.
When I try to used it for asynchronous call, the working thread is blocked and waits for the callback to be called. But, as I read in documentation, the current thread should continue to run and the callback method should be invoked by a different thread once the response is back from the server.
[UPDATE] Actually getting the response back from the server is where the current thread is blocked, and when I check the thread IDs, the thread which calls the callback is the same thread who sent the request.
Any idea what I might be missing?
Here's a snippet of the code:
public class MyRequestState
{
public WebRequest Request;
public WebResponse Response;
public ManualResetEvent allDone = new ManualResetEvent(false);
public MyRequestState()
{
Request = null;
Response = null;
}
}
public class SendRequest
{
private void ResponseCallback(IAsyncResult result)
{
//do sth ...
state.Response = (HttpWebResponse)request.EndGetResponse(result);
//do sth ...
state.allDone.Set();
}
public void MakeWebRequestAsync(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.Proxy = null;
state state = new MyRequestState();
state.Request = request;
IAsyncResult result = request.BeginGetResponse(new System.AsyncCallback(ResponseCallback), state);
state.allDone.WaitOne();
}
}

WebRequest.BeginGetResponse wait for connection synchronously and then receive data asynchronously. If the connection takes some times, it will freeze the calling thread for a while.

You are waiting on your ManualResetEvent right after starting the request. That's why your thread blocks. The thread isn't being signaled to continue until your completed callback is called.

Related

C# async await for pooling

I need to do some WebRequest to a certain endpoint every 2 seconds. I tried to do it with a Timer, the problem is that every call to the callback function is creating a different Thread and I'm havind some concurrence problems. So I decided to change my implementation and I was thinking about using a background worker with a sleep of two seconds inside or using async await but I don't see the advantages of using async await. Any advice? thank you.
This is the code that I will reimplement.
private void InitTimer()
{
TimerCallback callback = TimerCallbackFunction;
m_timer = new Timer(callback, null, 0, m_interval);
}
private void TimerCallbackFunction(Object info)
{
Thread.CurrentThread.Name = "Requester thread ";
m_object = GetMyObject();
}
public MyObject GetMyObject()
{
MyObject myobject = new MyObject();
try
{
MemoryStream responseInMemory = CreateWebRequest(m_host, ENDPOINT);
XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyObject));
myObject = (MyObject) xmlSerializer.Deserialize(responseInMemory);
}
catch (InvalidOperationException ex)
{
m_logger.WriteError("Error getting MyObject: ", ex);
throw new XmlException();
}
return myObject;
}
private MemoryStream CreateWebRequest(string host, string endpoint)
{
WebRequest request = WebRequest.Create(host + endpoint);
using (var response = request.GetResponse())
{
return (MemoryStream) response.GetResponseStream();
}
}
EDIT: I have read this SO thread Async/await vs BackgroundWorker
async await is also concurrence. If you have concurrence problems and you want your application to have only one thread, you should avoid using async await.
However the best way to do WebRequest is to use async await, which does not block the main UI thread.
Use the bellow method, it will not block anything and it is recommended by Microsoft. https://msdn.microsoft.com/en-us/library/86wf6409(v=vs.110).aspx
private async Task<MemoryStream> CreateWebRequest(string host, string endpoint)
{
WebRequest request = WebRequest.Create(host + endpoint);
using (var response = await request.GetResponseAsync())
{
return (MemoryStream)response.GetResponseStream();
}
}
You don't mention what the concurrency problems are. It may be that the request takes so long that the next one starts before the previous one finishes. It could also be that the callback replaces the value in my_Object while readers are accessing it.
You can easily make a request every X seconds, asynchronously and without blocking, by using Task.Delay, eg:
ConcurrentQueue<MyObject> m_Responses=new ConcurrentQueue<MyObject>();
public async Task MyPollMethod(int interval)
{
while(...)
{
var result=await SomeAsyncCall();
m_Responses.Enqueue(result);
await Task.Delay(interval);
}
}
This will result in a polling call X seconds after the last one finishes.
It also avoids concurrency issues by storing the result in a concurrent queue instead of replacing the old value, perhaps while someone else was reading int.
Consumers of MyObject would call Dequeue to retrieve MyObject instances in the order they were received.
You could use the ConcurrentQueue to fix the current code too:
private void TimerCallbackFunction(Object info)
{
Thread.CurrentThread.Name = "Requester thread ";
var result=GetMyObject();
m_Responses.Enqueue(result);
}
or
private async void TimerCallbackFunction(Object info)
{
Thread.CurrentThread.Name = "Requester thread ";
var result=await GetMyObjectAsync();
m_Responses.Enqueue(result);
}
if you want to change your GetObject method to work asynchronously.
Since your request seems to take a long time, it's a good idea to make it asynchronous and avoid blocking the timer's ThreadPool thread while waiting for a network response.

HttpWebRequest.BeginGetResponse does not work. Test becomes stuck

I've been trying to use HttpWebRequest.BeginGetResponse but it becomes stuck after CountdownEvent.Wait() is called. Using HttpClient I am not encountering the problem
private static CountdownEvent latch;
[TestMethod]
public void Test001()
{
latch = new CountdownEvent(1);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.google.com");
request.BeginGetResponse(new AsyncCallback(Finish), request);
latch.Wait();
}
private void Finish(IAsyncResult result)
{
Debug.WriteLine("FINISH");
latch.Signal();
}
The problem most likely comes from the fact that HttpWebRequest.BeginGetResponse(...) needs the UI thread at some point (not synchronously). I don't know why is it like that, but it is how it is.
In your case, the method Test001() is most likely called in the UI thread. On the latch.Wait(); line it blocks the thread, and so the request can't actually be made and it never completes.
If you could invoke the Test001() method on non-UI thread, it should work. Can't help you much more than this, as I don't really know how that unit test framework works.
Can you just try this..
[TestMethod]
public async Task Test001()
{
latch = new CountdownEvent(1);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.google.com");
request.BeginGetResponse(new AsyncCallback(Finish), request);
await latch;
}

WebRequest doomed to failure when starting from parallel thread

Consider following console application:
public static void Request(string url)
{
ThreadPool.QueueUserWorkItem((state) =>
{
try
{
var request = WebRequest.Create(url);
request.Timeout = 5000;
request.GetResponse();
}
catch (Exception e)
{
Console.Out.WriteLine(e);
}
Console.Out.WriteLine(url);
});
}
static void Main(string[] args)
{
Request("http://google.com?q=a");
Request("http://google.com?q=b");
Request("http://google.com?q=c");
Request("http://google.com?q=d");
Thread.Sleep(20000);
Console.In.ReadLine();
}
Output will finish for 2 urls. But for the rest it will throw "The operation has timed out".
I know that there is a limit of parallel connections by default set to two. If I increase it to three then three will finish up.
I.E:
ServicePointManager.DefaultConnectionLimit = 3;
But my question is - why the rest of them doesn't finish up, but throws the operation has timed out instead ?
Because the timeout includes the time the process was waiting in line for a connection to become available.
The timeout to represents "I want to wait at most 5000ms after I call GetResponse() to get my response" not "I want to wait at most an additional 5000ms after GetResponse() has waited for a unlimited amount of time to get its turn in the queue."
Now, you wonder, "but the query is so quick, it should not take more than 5000ms to complete!". The problem comes from the fact you did not close the response you got from GetResponse, from the MSDN:
You must call the Close method to close the stream and release the
connection. Failure to do so may cause your application to run out of
connections.
Calling Dispose() implicitly calls Close(), so if you update your code to dispose of your response then the used connection will become freed and one of the waiting requests will then be able to start up.
public static void Request(string url)
{
ThreadPool.QueueUserWorkItem((state) =>
{
try
{
var request = WebRequest.Create(url);
request.Timeout = 5000;
using(var response = request.GetResponse())
{
Console.Out.WriteLine("Response - " + url);
}
}
catch (Exception e)
{
Console.Out.WriteLine(e);
}
Console.Out.WriteLine("Method End - " + url);
});
}
static void Main(string[] args)
{
Request("http://google.com?q=a");
Request("http://google.com?q=b");
Request("http://google.com?q=c");
Request("http://google.com?q=d");
Thread.Sleep(20000);
Console.In.ReadLine();
}

WP7 Propogate exception from BeginGetResponse callback

I'm using HttpWebRequest to call a web service. If the AsyncCallback from BeginGetResponse throws an error, I want to propagate it up to my main program flow. I'm having trouble doing this because the error doesn't get propagated beyond the AsyncCallback. I've tried putting try/catch blocks at each step of the HttpWebRequest chain, but it never propagates beyond the "ResponseCallBack" method. Is it possible to get it back to the main thread?
private void StartRequest()
{
// Code to create request object is here
// ...
httpRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), httpRequest);
}
private void GetRequestStreamCallback(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
// End the operation
var postStream = request.EndGetRequestStream(result);
string body = GenerateRequestBody();
// Convert the string into a byte array
byte[] postBytes = Encoding.UTF8.GetBytes(body);
// Write to request stream
postStream.Write(postBytes, 0, postBytes.Length);
postStream.Close();
// Start the asynchronous operation to get the resonse
try
{
request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);
}
catch (Exception)
{
throw;
}
}
private void ResponseCallback(IAsyncResult result)
{
string contents = String.Empty;
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
using (Stream stream = response.GetResponseStream())
using (StreamReader reader = new StreamReader(stream))
{
contents = reader.ReadToEnd();
}
// Check the status
if (response.StatusCode == HttpStatusCode.OK)
{
//EXCEPTION NEVER MAKES IT PASSED HERE, EVEN IF I HAVE IT IN A TRY/CATCH BLOCK AND RE-THROW IT.
_object = ProcessResponseEntity(contents);
}
}
I think you're getting confused about the way asynchronous code exectution works and how the callback execution fits in with the calling code.
Within GetRequestStreamCallback, after the call to request.BeginGetResponse the method will continue to execute and in your example just end.
It is not known when (or even if) ResponseCallback will execute or what will be happening on the UI thread when it does. Because of this, ResponseCallback will execute on a different thread.
It's possible to have code within the callback run on the UI thread (which you'll need to do you want to interact with the UI) by using Dispatcher.BeginInvoke. However you can't have this execute within the context of another method.
While I wouldn't recommend it, you may want to have a look at this discussion on making the callback appear to execute synchronously. This will block your UI thread though and so is NOT recommended.

UnauthorizedAccessException: Invalid cross-thread access in Silverlight application (XAML/C#)

Relatively new to C# and wanted to try playing around with some third party web service API's with it.
Here is the XAML code
<Grid x:Name="ContentGrid" Grid.Row="1">
<StackPanel>
<Button Content="Load Data" Click="Button_Click" />
<TextBlock x:Name="TwitterPost" Text="Here I am"/>
</StackPanel>
</Grid>
and here is the C# code
private void Button_Click(object sender, RoutedEventArgs e)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://api.twitter.com/1/users/show/keykoo.xml");
request.Method = "GET";
request.BeginGetResponse(new AsyncCallback(twitterCallback), request);
}
private void twitterCallback(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
TextReader reader = new StreamReader(response.GetResponseStream());
string strResponse = reader.ReadToEnd();
Console.WriteLine("I am done here");
TwitterPost.Text = "hello there";
}
I'm guessing that this is caused by the fact that the callback executes on a separate thread than the UI? What is the normal flow to deal with these types of interactions in C#?
Thanks.
A useful way to get easy cross thread access with the CheckAccess call is to wrap up a utility method in a static class - e.g.
public static class UIThread
{
private static readonly Dispatcher Dispatcher;
static UIThread()
{
// Store a reference to the current Dispatcher once per application
Dispatcher = Deployment.Current.Dispatcher;
}
/// <summary>
/// Invokes the given action on the UI thread - if the current thread is the UI thread this will just invoke the action directly on
/// the current thread so it can be safely called without the calling method being aware of which thread it is on.
/// </summary>
public static void Invoke(Action action)
{
if (Dispatcher.CheckAccess())
action.Invoke();
else
Dispatcher.BeginInvoke(action);
}
}
then you can wrap any calls that update the UI where you may be on a background thread like so:
private void twitterCallback(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
TextReader reader = new StreamReader(response.GetResponseStream());
string strResponse = reader.ReadToEnd();
UIThread.Invoke(() => TwitterPost.Text = "hello there");
}
This way you don't have to know whether you are on a background thread or not and it avoids the overhead of adding methods to every control to check this.
Another way to do this is to use the this.Dispatcher.CheckAccess() function. It is the same as what you get in WPF but it doesn't show up in your intellisense so you may not have seen it. What you do is check if you have access to the UI thread, and if you don't you recursively call yourself back on the UI thread.
private void twitterCallback(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
TextReader reader = new StreamReader(response.GetResponseStream());
string strResponse = reader.ReadToEnd();
Console.WriteLine("I am done here");
////TwitterPost.Text = "hello there";
postMyMessage(TwitterPost.Text);
}
private void postMyMessage(string text)
{
if (this.Dispatcher.CheckAccess())
TwitterPost.Text = text;
else
this.Dispatcher.BeginInvoke(new Action<string>(postMyMessage), text);
}
This is just a very simple example and can get unmanageable once you have more than a few controls. For some WPF/Silverlight stuff i have used a generic function which also takes the UI control to be updated as well as the update itself, that way i don't have one of these functions for every control on the page that may need updating from the results of a background thread.
As you guessed, silverlight executes all web request asynchronously on a separated thread to avoid freezing the UI.
To dispatch messages to the UI thread you can use the Deployment.Current.Dispatcher.BeginInvoke(delegate, object[]) method.

Categories

Resources