HttpWebRequest.BeginGetResponse does not work. Test becomes stuck - c#

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;
}

Related

SemaphoreSlim deadlocks on 9th thread

I have a test automation environment with multithreaded tests that use a shared HttpClient to test methods on our Web API. After the HttpClient has been initialized, it can be used by all of our tests running on multiple threads, since it is a thread safe object. However, keeping the initialization from happening more than once is a challenge. Furthermore, it includes the await keyword in it, so it cannot use any basic lock technology to ensure the initialization operation is atomic.
To make sure the initialization happens properly, I am using a SemaphoreSlim to create a mutex for initialization. To get access to the object, all tests have to call a function that uses the SemaphoreSlim to make sure it has been properly initialized by the first thread to request it.
I found the following implementation for using SemaphoreSlim on this web page.
public class TimedLock
{
private readonly SemaphoreSlim toLock;
public TimedLock()
{
toLock = new SemaphoreSlim(1, 1);
}
public LockReleaser Lock(TimeSpan timeout)
{
if (toLock.Wait(timeout))
{
return new LockReleaser(toLock);
}
throw new TimeoutException();
}
public struct LockReleaser : IDisposable
{
private readonly SemaphoreSlim toRelease;
public LockReleaser(SemaphoreSlim toRelease)
{
this.toRelease = toRelease;
}
public void Dispose()
{
toRelease.Release();
}
}
}
I use this class like so:
private static HttpClient _client;
private static TimedLock _timedLock = new();
protected async Task<HttpClient> GetClient()
{
using (_timedLock.Lock(TimeSpan.FromSeconds(600)))
{
if (_client != null)
{
return _client;
}
MyWebApplicationFactory<Startup> factory = new();
_client = factory.CreateClient();
Request myRequest = new Request()
{
//.....Authentication code
};
HttpResponseMessage result = await _client.PostAsJsonAsync("api/accounts/Authenticate", myRequest);
result.EnsureSuccessStatusCode();
AuthenticateResponse Response = await result.Content.ReadAsAsync<AuthenticateResponse>();
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Response.Token);
return _client;
}
}
It worked flawlessly until just recently, when I added a ninth thread to my code. I've had to dial that back to 8 threads, because whenever I allow a 9th thread to call the TimedLock.Lock method, the entire program deadlocks.
Does anyone know what might be going on, or how to work around this problem?
OK. I figured out my own problem, and it really was MY own problem, nobody else's.
If you compare my code above really closely to the source that I quoted as getting it from, you'll notice there's actually a difference. The original code implements the Lock function asynchronously using the WaitAsync function built into SemaphoreSlim:
public async Task<LockReleaser> Lock(TimeSpan timeout)
{
if(await toLock.WaitAsync(timeout))
{
return new LockReleaser(toLock);
}
throw new TimeoutException();
}
And of course, in my code that uses it, add the await keyword at the proper place to take care of the added Task object properly:
...
using (await _timedLock.Lock(TimeSpan.FromSeconds(6000)))
{
...
Yesterday I "discovered" that if I changed the toLock object to use WaitAsync, the problem magically went away, and I was SO proud of myself. But then just a few minutes ago, when I was copying and pasting the "original" code into my question, I realized that the "original" code actually included "my" fix!
I now remember looking at this a few months ago and wondering why they needed to make this an Async function. So in my superior wisdom, I tried it without the Async, saw that it worked fine, and continued on until I just recently started using enough threads to demonstrate why it is necessary!
So to keep from confusing people, I changed the code in my question to be the bad code that I originally changed it to be, and put the truly original good code above here in "my" answer, which actually should be credited to Richard Blewett, the author of the referenced article.
I can't say I completely understand why this fix actually works, so any further answers that can explain it better are more than welcome!

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.

How to implement call to call ExecuteAsync using RestSharp

I am trying to call a REST service using RESTSharp and continuing execution immediately as I just need a task started but need to continue execution immediately so I am trying to use ExecuteAsync instead of Execute.
My code should look like this now
IRestResponse<ExpandoObject> restResponse = client.ExecuteAsync<ExpandoObject>(restRequest, response =>
{
callback(response.Content);
});
However, I have no idea how to implement the callback function and all samples don't show it. I assume it is like this but it does not compile.
private IRestResponse<ExpandoObject> callback(string content)
{
return null;
}
Any ideas?
There are a few ways to implement what you're trying to do, but the it looks like your
callback has wrong method signature...to get something "basic" running, the following should work
(I added wait simply for testing):
EventWaitHandle resetEvent = new AutoResetEvent(false);
client.ExecuteAsync(request, response =>
{
callback(response.Content);
resetEvent.Set();
return;
});
resetEvent.WaitOne();
}
private static void callback(string content)
{
System.Console.WriteLine(content);
}

Background Agent notifyComplete() after HTTPRequest

I want to create an HTTPRequest on a periodic task in a windows phone 7 background agent.
To keep it simple I just want to call a method on a shared class between the backgroundAgent and the application.
The shared method is a simple HTTPRequest.
On the SharedClass.cs makeTheRequest()
public static void makeTheRequest(){
var request = (HttpWebRequest)WebRequest.Create(new Uri("http://foo.bar"));
request.BeginGetResponse(r =>
{
NotifyComplete();
}, request);
}
I cannot call the notifyComplete() here because is not in the scope.
On the BackgroundAgent.cs onInvoke()
protected override void OnInvoke(ScheduledTask task)
{
if (task is PeriodicTask)
{
SharedClass.makeTheRequest();
NotifyComplete();
}
}
When I call it here, probably makeTheRequest() never gets done because the process is killed before it gets completed
I have read something about Taks Parallel library, but I don't know if thas is the right way to do it nor how to do it.
thanks
I'd change your makeTheRequest() method so that you can pass it an Action to fire upon request completion.
In the call from the agent you can include the call to NotifyComplete() but from the app you don't do this.
Note also that you should include timeout handling in the agent as repeated failing of the request from within the agent, due to timing out, can lead to the agent being disabled.
Update
An Example:
protected override void OnInvoke(ScheduledTask task)
{
if (task is PeriodicTask)
{
SharedClass.makeTheRequest(this.NotifyComplete);
}
}
public class SharedClass
{
public static void makeTheRequest(Action callback)
{
var request = (HttpWebRequest)WebRequest.Create(new Uri("http://foo.bar"));
request.BeginGetResponse(r => callback.Invoke(), request);
}
}
Once the main bgAgent thread exits, the HttpWebRequest will be killed.
We should be using synchronous HttpWebRequest here, but we can't because MS took them away from gelded framework.
We have to mimic thread-blocking behaviour using thread synchronization objects, like
ManualResetEvent.
protected override void OnInvoke(ScheduledTask task)
{
var evnt = new ManualResetEvent(false);//initialize to unsignalled state (false)
var request = (HttpWebRequest)WebRequest.Create(new Uri("http://foo.bar"));
request.BeginGetResponse(r =>
{
//do work here
evnt.Set();//signal main thread to continue
}, request);
evnt.WaitOne();//block execution of main thread
NotifyComplete();
return;
}
This way neither main thread will exit not NotifyComplete will be called before you finish your work.
You should make that WaitOne with a timeout (around 25 seconds) to ensure your task won't get killed and (worse) unsheduled because of 30 secs limit. This will make things much more complicated, as you'll have to protect your both threads (main and http) from messing each other up.
The evnt.Close() issue is also not shown here. Main thread may close the handle before http finishes and tries to Set(). Or you can rely on garbage collection Do I need to call Close() on a ManualResetEvent?
(btw, ManualResetEvent has nothing to do with concept of C# event. It's and event in Win32 sense, from same gang as Mutex and Semaphore).
You MUST use Delegate
In SharedClass.cs
public delegate void MyDelegate();
public MyDelegate MyUpdate;
In BackgroundAgent.cs
Maybe
void UpdateLiveTile() { ..... NotifyComplete(); }
In BackgroundAgent.cs onInvoke()
var cs = new SharedClass();
cs.MyUpdate= new SharedClass.MyDelegate(UpdateLiveTile);
cs.makeTheRequest();
In public static void makeTheRequest()
public static void makeTheRequest()
{
var request ....
request.BeginGetResponse(r =>
{
.........
MyUpdate();
}, request

WebRequest.BeginGetResponse does not work asynchronously

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.

Categories

Resources