Question

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);
}
Was it helpful?

Solution

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.

OTHER TIPS

Let me first preface by saying I am completely unfamiliar with IHttpAsyncHandler interface and usage.

That being said, in general when using an asynchronous programming model, each AsyncResult represents a specific asynchronous method call and should not be reused. Seems like you are looking more for a RegisterEvent(callback) method than a BeginProcessing(callback method) - so even if you were able to get this to work, the design does not hold by asynchonous programming best practices (IMHO).

I assume that since you are using http which is request/response based, it seems unlikely that you will be able to push multiple responses for one request and even if you were able to somehow hack this up, your client will eventually get a timeout due to its unanswered request which would be problematic for what you are going for.

I know in Remoting you can register for remote events and WCF supports duplex contracts which can enable "push technology" if this is an option for you.

Good luck.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top