Click here to Skip to main content
15,886,110 members
Articles / Web Development / ASP.NET
Article

Yield, Web Continuations!

Rate me:
Please Sign up or sign in to vote.
4.38/5 (10 votes)
7 Aug 2006MIT2 min read 29.4K   201   26   4
Article shows how to emulate web continuation in .NET framework

Introduction

The article shows how to emulate web continuation in .NET framework. It makes the creation of complex flow in web applications possible.

Background

A continuation is a representation of the execution state of a program at a certain point. Not all languages can support continuations. Saving of the state in web application gives additional difficulty.

Iterator block was introduced in C# 2.0. It can be presented as a method body that returns one of the generic enumerator (enumerable) interfaces and contains at least one yield statement. Following example shows how iterator block is working. The function saves all internal variables and returns control to caller on yield return statement; the function restores state and resumes execution when another value is requested.

C#
static IEnumerable<int> Fibonacci(int n)
{
    int previous = 0;
    int current = 1;
    for (int i = 0; i < n; i++)
    {
        yield return current;
        int next = previous + current;
        previous = current;
        current = next;
    }
}
...
// Prints 1 1 2 3 5 8 13 21 34 55
foreach (int i in Fibonacci(10))  Console.WriteLine(i);

The enumerator saves local variables and execution resume point in memory, but it doesn’t allow exporting and importing of the state to and from an external stream. It’s the reason why it cannot be used as true web continuation solution.

Using the code

Web continuation manager implemented as ContinuationManager server control for .NET framework (v2.0.50727). The ASPX page that uses continuation has to contain this control.

As example, we will implement number guessing game using natural execution flow. Let’s declare iterator block inside page code behind class:

C#
private IEnumerator<object> NumberGuess()
{
    Random random = new Random(); // generate random number
    int answer = random.Next(1, 101);
    int attempts = 1;

    mainMultiView.SetActiveView(guessView);
    lastGuessPanel.Visible = false;
    yield return null; // store and return control

    while(guess != answer)
    {
        ++attempts;
        lastGuessPanel.Visible = true;
        lastGuessLabel.Text = guess.ToString();

        lowerLabel.Visible = guess < answer;
        higherLabel.Visible = guess > answer;
        yield return null; // store and return control
    }

    mainMultiView.SetActiveView(resultView);
    guessedNumberLabel.Text = answer.ToString();
    attemptsLabel.Text = attempts.ToString();
}

We have to register enumerator with ContinuationManager control and then make first call.

C#
controlManager.Register(NumberGuess());
controlManager.Call();

It will update continuation data in ViewState container and return control immediately after first yield return statement. After that page will be rendered and submitted to the browser.

Execution flow using web continuation

When next request is being processed continuation will restore itself form ViewState and all you need to do is make another call to continue execution of the interrupted code. Since enumerator instance refers to current page the user interface can be changed to display new input controls or messages.

Points of Interest

Full description of C# 2.0 “unfolding” of iterator block into enumerator can be found in “C# 2.0 Specification”. We can notice that the enumerator contains all the local variables, pointer to class that declares that method (unless the method is static), state and current returned value. The enumerator type is declared as private nested class. The enumerator data can be imported and exported using System.Reflection classes. (see implementation of Continuation<T> class)

ContinuationManager server control should be located on the control that declares iteration block. That helps to automatically find the owner control of the restored enumerator.

Special attention is required for objects that implements IDisposable interface. Usually a IDisposable object isn’t marked as Serializable therefore it is impossible to import/export its state. However the objects can be used between yield statements.

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralVery Interesting Pin
Jeffster30-Aug-07 9:30
Jeffster30-Aug-07 9:30 
GeneralRe: Very Interesting Pin
notmasteryet6-Oct-07 5:54
notmasteryet6-Oct-07 5:54 
Session and cache can be used. Using of viewstate will guarantee that state will be serialized and not staying in server memory.
GeneralSample code Pin
gonser8-Aug-06 10:41
gonser8-Aug-06 10:41 
AnswerRe: Sample code Pin
notmasteryet8-Aug-06 12:48
notmasteryet8-Aug-06 12:48 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.