Jul 162006
 
A few weeks ago I blogged about asyncronous web parts. In preparation for my July 24 presentation for the Denver .NET User Group and another ongoing project, the Portalbuilder.org SharePoint 2007 SDK, I’ve released some code samples and framework application blocks over at workspaces.gotdotnet.com/sharepointconnections. This code works great for all types of web components– pages that serve as simple Xml endpoints, controls deployed on pages, WebParts and user controls.
 
Let’s first talk about the problem that async ASP.NET solves. I saw a pretty good session on this at DevConnections in Orlando, and there’s also a great summary of the problem in July’s MSDN magazine where Jeff Prosise wrote a little bit about Thread Pool Saturation:
Suffice it to say that ASP.NET relies on a finite thread pool to process requests, and if all the threads are occupied waiting for database queries, Web service calls, or other I/O operations to complete, additional requests must be queued up until an operation completes and a thread is freed. Performance drops off precipitously when requests are queued. And if the queue fills up, ASP.NET fails subsequent requests with HTTP 503 errors.
With SharePoint 2007, by default pages don’t run in Async mode. But never fear, WebParts that are programmed asyncronously will still run asynchronously regardless of the page settings. In my asynchronous WebPart, I adde some simple debug statements (using Literal controls) in the CreateChildControls method, the OnLoad method, and my GetData method which executes within the registered async task.
this.Page.IsAsync=False (CreateChildControls)
ManagedThreadId=9 (OnLoad)
ManagedThreadId=12 (GetData)
As you can see– the Page is not async, but the GetData operation was kicked off to another managed thread for operation. This is quite valuable for Web Parts that might be doing/calling very different things on your portal pages!
 
When we register async tasks, we are either going to call objects that implement the async design pattern of BeginFoo and EndFoo methods using the IAsyncResult interface, or we can simply implement that interface in the web component itself. Before we look at the web part code, let’s look at a simple asynchronous class:
public class AsyncManager
{
    private RunDelegate runner;
    private delegate void RunDelegate();

    /// Does the work 
    private void Run(){}

     public IAsyncResult BeginRun(AsyncCallback callback, object state){
         runner = new RunDelegate(Run);
         IAsyncResult result = runner.BeginInvoke(callback, state);
        return result;
    }

     public void EndRun(IAsyncResult result){
         runner.EndInvoke(result);
    }
}
Notice that the caller would call BeginRun and EndRun through the asycnronous calling code (typically Page.RegisterAsyncTask()). This is a good pattern to strive for in your data manager libraries and middle tier code, where a caller could call your method async or synchronously.
 
Taking this a step farther, we can push this down into our base Web Part, so the developer implementing a web part has an easy pattern to follow, and exception handling of the async code is pushed down to a framework level. To do this, we simply implement the async pattern above into the web part itself. The OnLoad override registers the task:
Page.RegisterAsyncTask( new PageAsyncTask( new System.Web.BeginEventHandler(this.BeginRun), new System.Web.EndEventHandler(this.EndRun), new System.Web.EndEventHandler(this.GetDataTimeout), null, true) );
 
 And the following async methods call the virtual or abstract method GetData, leaving no async code directly to the end developer to implement:
 

private

IAsyncResult BeginRun(object src, EventArgs args, AsyncCallback callback, object state){
  doSomethingCaller = new DoSomethingDelegate(SafeGetData);
 
IAsyncResult result = doSomethingCaller.BeginInvoke(callback, state);
 
return result;
}

private

void EndRun(IAsyncResult result){
 
doSomethingCaller.EndInvoke(result);
}

protected

virtual void GetData() { }

private

void SafeGetData(){
  try{
 
this.GetData();
  }catch (Exception ex){ this.exceptions.Add(ex); }
} 

 
And then in our concrete class, we simply inherit from the EnterpriseWebPart (we call it "enterprise" because we can charge more money for "enteprise" than "professional", of course!) and implement the GetData() method. And since we know that GetData is wrapped in the base class for error handling, we’re sure to catch any out of thread exceptions that happen. So the guts of the aync webpart that the developer code is something as simple as this:
 

public class ExampleWebPart : EnterpriseWebPart, IWebPart{
  
protected override void GetData(){
    
// Call your database or webservice operations here. If you use async methods, use the WaitHandle.
   }
}

 
The full code for this is available at workspaces.gotdotnet.com/sharepointconnections. It’s in the 7/12/2006 release of my WebPartFramework Preview. 

  One Response to “Asynchrounous ASP.NET WebParts for SharePoint/MOSS”

  1. Hi, I have followed your post workflow BUT the page is not processed asynchronous. I t waits for the job to finish then is rendered. I suppose this is because of the async property of the page. The problem is that in my web part solution I don’t have default.aspx page. Where I can set the async property?

    Thanks!

 Leave a Reply

(required)

(required)

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>