Recently, I successfully created a long-polling service using HttpAsyncHandler’s. During the development it came to me (that) I “might” be able to re-use the AsyncResult object many times without long-polling repeatedly. If possible, I could then “simulate” push-technology by re-building or re-using the AsyncResult somehow (treating the first request as though it were a subscription-request).
Of course, the first call works great, but subsequent calls keep giving me “Object not set to an instance of an object”. I am “guessing” it is because certain objects are static, and therefore, once "completed" cannot be reused or retrieved (any insight there would be AWESOME!).
So the question is…
Is it possible to build dynamically a new callback from the old callback?
The initial "subscription" process goes like this:
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
Guid id = new Guid(context.Request["Key"]);
AsyncResult request = new AsyncResult(cb, context, id);
Service.Singleton.Subscribe(request);
return request;
}
Here is an example of what the service does:
private void MainLoop()
{
while (true)
{
if (_subscribers.Count == 0)
{
if (_messages.Count == max)
_messages.Clear();
}
else
{
if (_messages.Count > 0)
{
Message message = _messages.Dequeue();
foreach (AsyncResult request in _subscribers.ToArray())
{
if(request.ProcessRequest(message));
_subscribers.Remove(request);
}
}
}
Thread.Sleep(500);
}
}
Here is an example of what the AsyncResult.ProcessRequest() call does:
public bool ProcessRequest(Message message)
{
try
{
this.Response = DoSomethingUseful(message);
this.Response.SessionValid = true;
}
catch (Exception ex)
{
this.Response = new Response();
this.Response.SessionValid = false;
}
this.IsCompleted = true;
_asyncCallback(this);
return this.IsCompleted;
}
SO...WOULD SOMETHING LIKE THIS BE POSSIBLE?
I literally tried this and it didn't work...but is SOMETHING "like" it possible?
AsyncResult newRequest = new AsyncResult(request.cb, request.context, request.id);
if(request.ProcessRequest(message))
{
_subscribers.Remove(request);
Subscribers.Add(newRequest);
}
IAsyncResult
implementations must satisfy certain invariants, one of which is that it can only be completed once. You don't identify the AsyncResult
you're using, but if it's Richter's famous version, then it would uphold that invariant.
If you don't want to go through the trouble of implementing the event-based asynchronous pattern, then the best option is Microsoft Rx, which is a true push-based system.