Team Foundation Server...

Team Foundation Server...

Agile Scrum Methodology

Use .NET's BackgroundWorker to Keep ASP.NET Cache in Sync with a SQL Server Database

Introduction
Storing frequently accessed database data, like lookup lists, in ASP.NET’s cache is a great way to optimize a web application’s performance. But anytime you store database data in ASP.NET’s cache, you have to provide a way to update that cache. This ensures changes made in the database make it into the web application’s cache. This is handled using either notifications or polling.

Notifications are possible when using SQL Server 2005 with notification services and .NET’s SqlDependency object from the System.Data.SqlClient namespace. But notification services aren’t available in SQL Server 2008 or other databases. Even if you are using SQL Server 2005, employing this technology requires more server configuration and therefore complicates deployment.

Polling is often handled by setting an expiration of the cached item at some time interval such as hourly. That way the cache holds the data for an hour and then automatically dumps it. Then when the data is requested and the cache is empty, the data is read from the database and placed back into the cache. This approach works fairly well, but with two drawbacks. First, it requires the cache be refreshed even when it is not needed. Second, it runs on the same thread as the request so some unlucky user has to wait a little longer for their request to return while the data is read from the database and stored in the cache.

The BackgroundWorker object in .NET enables a better solution. When the web application starts, it spins off a background thread, and passes to it the application’s HttpContext object, enabling the thread, access to the application’s cache. When the web application ends, it stops the background thread. The background thread runs a continuous loop of sleeping for some time interval, and then polls the database to see if data has changed during that interval. If data has changed, the cache is refreshed. This solution is highly efficient because it runs on a background thread and refreshes the cache only when needed.

Writing CLS-Compliant Code




























MSDN
MSDN Library
Visual Studio 2008
Visual Studio
 Writing CLS-Compliant Code





Collapse All/Expand All
Collapse All












This page is specific to

Microsoft Visual Studio 2008/.NET Framework 3.5

Other versions are also available for the following:






.NET Framework Developer's Guide
Writing CLS-Compliant Code


Common Language Specification (CLS) compliance generally refers to the claim that CLS rules and restrictions are being followed. However, the concept has a more specific meaning depending on whether you are describing CLS-compliant code or CLS-compliant development tools, such as a compiler. CLS-compliant tools can help you write CLS-compliant code.


If you want your code to be CLS-compliant, you must expose functionality in a way that is CLS-compliant in the following places:

  • Definitions of your public classes.

  • Definitions of the public members of public classes, and of members accessible to derived classes (family access).

  • Parameters and return types of public methods of public classes, and of methods accessible to derived classes.

The features you use in the definitions of your private classes, in the definitions of private methods on public classes, and in local variables do not have to follow the CLS rules. You can also use any language features you want in the code that implements your class and still have a CLS-compliant component.

NoteNote:

Jagged arrays — that is, arrays of arrays — are CLS-compliant. In the .NET Framework version 1.0, the C# compiler mistakenly reports that they are not.

You can mark assemblies, modules, types, and members as either CLS-compliant or not CLS compliant using the CLSCompliantAttribute. All assemblies that are intended to be CLS-compliant should be marked as such. An assembly that is not marked as CLS-compliant is considered to be not CLS compliant. If no CLS attribute is applied to a type, that type is assumed to have the same CLS compliance as the assembly in which the type is defined. Similarly, if no CLS attribute is applied to a member, the member is considered to have the same CLS compliance as the type that defines it. You cannot mark a program element as CLS-compliant if its enclosing element is not marked as CLS-compliant. The example at the end of this topic illustrates the use of the CLSCompliantAttribute.

Assemblies, modules, and types can be CLS-compliant even if some parts of the assembly, module, or type are not CLS-compliant, as long as two conditions are met:

  • If the element is marked as CLS-compliant, the parts that are not CLS-compliant must be marked using the CLSCompliantAttribute with its argument set to false.

  • A comparable CLS-compliant alternative member must be supplied for each member that is not CLS-compliant.

If you design a CLS–compliant class library, your library will have a guarantee of interoperability with a wide range of programming languages; therefore, your library is likely to have a wider customer base than a version that is not CLS-compliant.

The .NET Framework provides a CLS-compliant class library. For more information about this class library, see .NET Framework Class Library.


Languages that target the runtime have agreed to support CLS features and follow the CLS rules directed to compilers. These language compilers simplify CLS compliance by making the CLS data types and features available for creating components. The levels of CLS compliance among compilers and other tools are described as follows:

  • CLS-compliant consumer tools.

    Consumer tools are languages that enable developers to access all the features supplied by CLS-compliant libraries. Developers using these languages might not be able to extend CLS-compliant libraries by creating new types, but they can use any type defined by a compliant library. This level of compliance can be useful when you want to access a .NET Framework class library, but do not need to author new objects for consumption by others, such as when you are using Web Forms on an ASP.NET page or creating a Windows Forms user interface.

  • CLS-compliant extender tools.

    Extender tools are languages that allow developers to both use and extend types defined in CLS-compliant libraries. Developers can use existing types as well as define new types. Extender tools must follow all the rules that consumer tools must follow, as well as some additional rules, which are described in the specification for the Common Language Infrastructure, Partition I - Architecture, available from the Microsoft Developer Network (MSDN) Web site.

When you design your own CLS-compliant components, it is helpful to use a CLS-compliant tool. Writing CLS-compliant components without this support is more difficult because otherwise you might not have access to all the CLS features you want to use.

Some CLS-compliant language compilers, such as the C# or Visual Basic compilers, enable you to specify that you intend your code to be CLS-compliant. These compilers can check for CLS compliance and let you know when your code uses functionality that is not supported by the CLS. The C# and Visual Basic compilers allow you to mark a program element as CLS-compliant, which will cause the compiler to generate a compile-time error if the code is not CLS-compliant. For example, the following code generates a compiler warning.



Visual Basic


<Assembly: CLSCompliant(True)>
 
<CLSCompliant(True)> Public Class MyCompliantClass
   Public Sub ChangeValue(value As UInt32)
   End Sub
 
   Public Shared Sub Main()
      Dim i As Integer = 2
      Console.WriteLine(i)
   End Sub   
End Class



using System;
 
// Assembly marked as compliant.
[assembly: CLSCompliant(true)]
 
// Class marked as compliant.
[CLSCompliant(true)]
public class MyCompliantClass {
   // ChangeValue exposes UInt32, which is not in CLS.
   // A compile-time warning results.
   public void ChangeValue(UInt32 value){ }
 
   public static void Main( ) {
   int i = 2;
   Console.WriteLine(i);
   }
}

This code generates the following C# warning:



warning CS3001: Argument type 'uint' is not CLS-compliant

or the following Visual Basic warning:



warning BC40028: Type of parameter 'value' is not CLS-compliant.

To remove the warning, you can indicate that ChangeValue is not compliant, as shown in the following example.



Visual Basic


' Assembly marked as compliant.
<Assembly: CLSCompliant(True)>
 
' Class marked as compliant.
<CLSCompliant(True)> Public Class MyCompliantClass
   ' Method marked as not compliant.
   <CLSCompliant(False)> Public Sub ChangeValue(value As UInt32)
   End Sub
 
   Public Shared Sub Main()
      Dim i As Integer = 2
      Console.WriteLine(i)
   End Sub   
End Class



using System;
 
// Assembly marked as compliant.
[assembly: CLSCompliantAttribute(true)]
 
// Class marked as compliant.
[CLSCompliantAttribute(true)]
public class MyCompliantClass {
   // Method marked as not compliant.
   [CLSCompliantAttribute(false)]
   public void ChangeValue(UInt32 value){ }
 
   public static void Main( ) {
   int i = 2;
   Console.WriteLine(i);
   }
}

This code produces no compiler warnings. The output is 2.

For more information about how to specify the CLS-compliance of your code, see the documentation for the language compiler you are using.











Tags

What's this?
:


Add a tag










Community Content  
What is Community Content?

Add new content

RSS 
Annotations










Processing






© 2010 Microsoft Corporation. All rights reserved.
Terms of Use
|
Trademarks
|
Privacy Statement







Page view tracker











BackgroundWorker Class

Visual Basic (Declaration) 
<HostProtectionAttribute(SecurityAction.LinkDemand, SharedState := True)> _
Public Class BackgroundWorker _
    Inherits Component
Visual Basic (Usage)
Dim instance As BackgroundWorker
C#
[HostProtectionAttribute(SecurityAction.LinkDemand, SharedState = true)]
public class BackgroundWorker : Component
Visual C++
[HostProtectionAttribute(SecurityAction::LinkDemand, SharedState = true)]
public ref class BackgroundWorker : public Component
JScript
public class BackgroundWorker extends Component
NoteNote:
The HostProtectionAttribute attribute applied to this type or member has the following Resources property value: SharedState. The HostProtectionAttribute does not affect desktop applications (which are typically started by double-clicking an icon, typing a command, or entering a URL in a browser). For more information, see the HostProtectionAttribute class or SQL Server Programming and Host Protection Attributes.
The BackgroundWorker class allows you to run an operation on a separate, dedicated thread. Time-consuming operations like downloads and database transactions can cause your user interface (UI) to seem as though it has stopped responding while they are running. When you want a responsive UI and you are faced with long delays associated with such operations, the BackgroundWorker class provides a convenient solution.
To execute a time-consuming operation in the background, create a BackgroundWorker and listen for events that report the progress of your operation and signal when your operation is finished. You can create the BackgroundWorker programmatically or you can drag it onto your form from the Components tab of the Toolbox. If you create the BackgroundWorker in the Windows Forms Designer, it will appear in the Component Tray, and its properties will be displayed in the Properties window.
To set up for a background operation, add an event handler for the DoWork event. Call your time-consuming operation in this event handler. To start the operation, call RunWorkerAsync. To receive notifications of progress updates, handle the ProgressChanged event. To receive a notification when the operation is completed, handle the RunWorkerCompleted event.
NoteNote:
You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the ProgressChanged and RunWorkerCompleted events.
BackgroundWorker events are not marshaled across AppDomain boundaries. Do not use a BackgroundWorker component to perform multithreaded operations in more than one AppDomain.
If your background operation requires a parameter, call RunWorkerAsync with your parameter. Inside the DoWork event handler, you can extract the parameter from the DoWorkEventArgs..::.Argument property.
For more information about BackgroundWorker, see How to: Run an Operation in the Background.


The following code example demonstrates the use of the BackgroundWorker class for executing a time-consuming operation asynchronously. The operation computes the selected Fibonacci number, reports progress updates as the calculation proceeds, and permits a pending calculation to be canceled.


Visual Basic
Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Threading
Imports System.Windows.Forms
 
Public Class FibonacciForm
    Inherits System.Windows.Forms.Form
 
    Private numberToCompute As Integer = 0
    Private highestPercentageReached As Integer = 0
 
    Private numericUpDown1 As System.Windows.Forms.NumericUpDown
    Private WithEvents startAsyncButton As System.Windows.Forms.Button
    Private WithEvents cancelAsyncButton As System.Windows.Forms.Button
    Private progressBar1 As System.Windows.Forms.ProgressBar
    Private resultLabel As System.Windows.Forms.Label
    Private WithEvents backgroundWorker1 As System.ComponentModel.BackgroundWorker
 
 
    Public Sub New()
        InitializeComponent()
    End Sub 'New
 
    Private Sub startAsyncButton_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) _
    Handles startAsyncButton.Click
 
        ' Reset the text in the result label.
        resultLabel.Text = [String].Empty
 
        ' Disable the UpDown control until 
        ' the asynchronous operation is done.
        Me.numericUpDown1.Enabled = False
 
        ' Disable the Start button until 
        ' the asynchronous operation is done.
        Me.startAsyncButton.Enabled = False
 
        ' Enable the Cancel button while 
        ' the asynchronous operation runs.
        Me.cancelAsyncButton.Enabled = True
 
        ' Get the value from the UpDown control.
        numberToCompute = CInt(numericUpDown1.Value)
 
        ' Reset the variable for percentage tracking.
        highestPercentageReached = 0
 
 
        ' Start the asynchronous operation.
        backgroundWorker1.RunWorkerAsync(numberToCompute)
    End Sub 
 
    Private Sub cancelAsyncButton_Click( _
    ByVal sender As System.Object, _
    ByVal e As System.EventArgs) _
    Handles cancelAsyncButton.Click
 
        ' Cancel the asynchronous operation.
        Me.backgroundWorker1.CancelAsync()
 
        ' Disable the Cancel button.
        cancelAsyncButton.Enabled = False
 
    End Sub 'cancelAsyncButton_Click
 
    ' This event handler is where the actual work is done.
    Private Sub backgroundWorker1_DoWork( _
    ByVal sender As Object, _
    ByVal e As DoWorkEventArgs) _
    Handles backgroundWorker1.DoWork
 
        ' Get the BackgroundWorker object that raised this event.
        Dim worker As BackgroundWorker = _
            CType(sender, BackgroundWorker)
 
        ' Assign the result of the computation
        ' to the Result property of the DoWorkEventArgs
        ' object. This is will be available to the 
        ' RunWorkerCompleted eventhandler.
        e.Result = ComputeFibonacci(e.Argument, worker, e)
    End Sub 'backgroundWorker1_DoWork
 
    ' This event handler deals with the results of the
    ' background operation.
    Private Sub backgroundWorker1_RunWorkerCompleted( _
    ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) _
    Handles backgroundWorker1.RunWorkerCompleted
 
        ' First, handle the case where an exception was thrown.
        If (e.Error IsNot Nothing) Then
            MessageBox.Show(e.Error.Message)
        ElseIf e.Cancelled Then
            ' Next, handle the case where the user canceled the 
            ' operation.
            ' Note that due to a race condition in 
            ' the DoWork event handler, the Cancelled
            ' flag may not have been set, even though
            ' CancelAsync was called.
            resultLabel.Text = "Canceled"
        Else
            ' Finally, handle the case where the operation succeeded.
            resultLabel.Text = e.Result.ToString()
        End If
 
        ' Enable the UpDown control.
        Me.numericUpDown1.Enabled = True
 
        ' Enable the Start button.
        startAsyncButton.Enabled = True
 
        ' Disable the Cancel button.
        cancelAsyncButton.Enabled = False
    End Sub 'backgroundWorker1_RunWorkerCompleted
 
    ' This event handler updates the progress bar.
    Private Sub backgroundWorker1_ProgressChanged( _
    ByVal sender As Object, ByVal e As ProgressChangedEventArgs) _
    Handles backgroundWorker1.ProgressChanged
 
        Me.progressBar1.Value = e.ProgressPercentage
 
    End Sub
 
    ' This is the method that does the actual work. For this
    ' example, it computes a Fibonacci number and
    ' reports progress as it does its work.
    Function ComputeFibonacci( _
        ByVal n As Integer, _
        ByVal worker As BackgroundWorker, _
        ByVal e As DoWorkEventArgs) As Long
 
        ' The parameter n must be >= 0 and <= 91.
        ' Fib(n), with n > 91, overflows a long.
        If n < 0 OrElse n > 91 Then
            Throw New ArgumentException( _
                "value must be >= 0 and <= 91", "n")
        End If
 
        Dim result As Long = 0
 
        ' Abort the operation if the user has canceled.
        ' Note that a call to CancelAsync may have set 
        ' CancellationPending to true just after the
        ' last invocation of this method exits, so this 
        ' code will not have the opportunity to set the 
        ' DoWorkEventArgs.Cancel flag to true. This means
        ' that RunWorkerCompletedEventArgs.Cancelled will
        ' not be set to true in your RunWorkerCompleted
        ' event handler. This is a race condition.
        If worker.CancellationPending Then
            e.Cancel = True
        Else
            If n < 2 Then
                result = 1
            Else
                result = ComputeFibonacci(n - 1, worker, e) + _
                         ComputeFibonacci(n - 2, worker, e)
            End If
 
            ' Report progress as a percentage of the total task.
            Dim percentComplete As Integer = _
                CSng(n) / CSng(numberToCompute) * 100
            If percentComplete > highestPercentageReached Then
                highestPercentageReached = percentComplete
                worker.ReportProgress(percentComplete)
            End If
 
        End If
 
        Return result
 
    End Function
 
 
    Private Sub InitializeComponent()
        Me.numericUpDown1 = New System.Windows.Forms.NumericUpDown
        Me.startAsyncButton = New System.Windows.Forms.Button
        Me.cancelAsyncButton = New System.Windows.Forms.Button
        Me.resultLabel = New System.Windows.Forms.Label
        Me.progressBar1 = New System.Windows.Forms.ProgressBar
        Me.backgroundWorker1 = New System.ComponentModel.BackgroundWorker
        CType(Me.numericUpDown1, System.ComponentModel.ISupportInitialize).BeginInit()
        Me.SuspendLayout()
        '
        'numericUpDown1
        '
        Me.numericUpDown1.Location = New System.Drawing.Point(16, 16)
        Me.numericUpDown1.Maximum = New Decimal(New Integer() {91, 0, 0, 0})
        Me.numericUpDown1.Minimum = New Decimal(New Integer() {1, 0, 0, 0})
        Me.numericUpDown1.Name = "numericUpDown1"
        Me.numericUpDown1.Size = New System.Drawing.Size(80, 20)
        Me.numericUpDown1.TabIndex = 0
        Me.numericUpDown1.Value = New Decimal(New Integer() {1, 0, 0, 0})
        '
        'startAsyncButton
        '
        Me.startAsyncButton.Location = New System.Drawing.Point(16, 72)
        Me.startAsyncButton.Name = "startAsyncButton"
        Me.startAsyncButton.Size = New System.Drawing.Size(120, 23)
        Me.startAsyncButton.TabIndex = 1
        Me.startAsyncButton.Text = "Start Async"
        '
        'cancelAsyncButton
        '
        Me.cancelAsyncButton.Enabled = False
        Me.cancelAsyncButton.Location = New System.Drawing.Point(153, 72)
        Me.cancelAsyncButton.Name = "cancelAsyncButton"
        Me.cancelAsyncButton.Size = New System.Drawing.Size(119, 23)
        Me.cancelAsyncButton.TabIndex = 2
        Me.cancelAsyncButton.Text = "Cancel Async"
        '
        'resultLabel
        '
        Me.resultLabel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D
        Me.resultLabel.Location = New System.Drawing.Point(112, 16)
        Me.resultLabel.Name = "resultLabel"
        Me.resultLabel.Size = New System.Drawing.Size(160, 23)
        Me.resultLabel.TabIndex = 3
        Me.resultLabel.Text = "(no result)"
        Me.resultLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter
        '
        'progressBar1
        '
        Me.progressBar1.Location = New System.Drawing.Point(18, 48)
        Me.progressBar1.Name = "progressBar1"
        Me.progressBar1.Size = New System.Drawing.Size(256, 8)
        Me.progressBar1.TabIndex = 4
        '
        'backgroundWorker1
        '
        Me.backgroundWorker1.WorkerReportsProgress = True
        Me.backgroundWorker1.WorkerSupportsCancellation = True
        '
        'FibonacciForm
        '
        Me.ClientSize = New System.Drawing.Size(292, 118)
        Me.Controls.Add(Me.progressBar1)
        Me.Controls.Add(Me.resultLabel)
        Me.Controls.Add(Me.cancelAsyncButton)
        Me.Controls.Add(Me.startAsyncButton)
        Me.Controls.Add(Me.numericUpDown1)
        Me.Name = "FibonacciForm"
        Me.Text = "Fibonacci Calculator"
        CType(Me.numericUpDown1, System.ComponentModel.ISupportInitialize).EndInit()
        Me.ResumeLayout(False)
 
    End Sub 'InitializeComponent
 
    <STAThread()> _
    Shared Sub Main()
        Application.Run(New FibonacciForm)
    End Sub 'Main
End Class 'FibonacciForm 
 


C#
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
 
namespace BackgroundWorkerExample
{    
    public class FibonacciForm : System.Windows.Forms.Form
    {    
        private int numberToCompute = 0;
        private int highestPercentageReached = 0;
 
        private System.Windows.Forms.NumericUpDown numericUpDown1;
        private System.Windows.Forms.Button startAsyncButton;
        private System.Windows.Forms.Button cancelAsyncButton;
        private System.Windows.Forms.ProgressBar progressBar1;
        private System.Windows.Forms.Label resultLabel;
        private System.ComponentModel.BackgroundWorker backgroundWorker1;
 
        public FibonacciForm()
        {    
            InitializeComponent();
 
            InitializeBackgroundWorker();
        }
 
        // Set up the BackgroundWorker object by 
        // attaching event handlers. 
        private void InitializeBackgroundWorker()
        {
            backgroundWorker1.DoWork += 
                new DoWorkEventHandler(backgroundWorker1_DoWork);
            backgroundWorker1.RunWorkerCompleted += 
                new RunWorkerCompletedEventHandler(
            backgroundWorker1_RunWorkerCompleted);
            backgroundWorker1.ProgressChanged += 
                new ProgressChangedEventHandler(
            backgroundWorker1_ProgressChanged);
        }
    
        private void startAsyncButton_Click(System.Object sender, 
            System.EventArgs e)
        {
            // Reset the text in the result label.
            resultLabel.Text = String.Empty;
 
            // Disable the UpDown control until 
            // the asynchronous operation is done.
            this.numericUpDown1.Enabled = false;
 
            // Disable the Start button until 
            // the asynchronous operation is done.
            this.startAsyncButton.Enabled = false;
 
            // Enable the Cancel button while 
            // the asynchronous operation runs.
            this.cancelAsyncButton.Enabled = true;
 
            // Get the value from the UpDown control.
            numberToCompute = (int)numericUpDown1.Value;
 
            // Reset the variable for percentage tracking.
            highestPercentageReached = 0;
 
            // Start the asynchronous operation.
            backgroundWorker1.RunWorkerAsync(numberToCompute);
        }
 
        private void cancelAsyncButton_Click(System.Object sender, 
            System.EventArgs e)
        {   
            // Cancel the asynchronous operation.
            this.backgroundWorker1.CancelAsync();
 
            // Disable the Cancel button.
            cancelAsyncButton.Enabled = false;
        }
 
        // This event handler is where the actual,
        // potentially time-consuming work is done.
        private void backgroundWorker1_DoWork(object sender, 
            DoWorkEventArgs e)
        {   
            // Get the BackgroundWorker that raised this event.
            BackgroundWorker worker = sender as BackgroundWorker;
 
            // Assign the result of the computation
            // to the Result property of the DoWorkEventArgs
            // object. This is will be available to the 
            // RunWorkerCompleted eventhandler.
            e.Result = ComputeFibonacci((int)e.Argument, worker, e);
        }
 
        // This event handler deals with the results of the
        // background operation.
        private void backgroundWorker1_RunWorkerCompleted(
            object sender, RunWorkerCompletedEventArgs e)
        {
            // First, handle the case where an exception was thrown.
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else if (e.Cancelled)
            {
                // Next, handle the case where the user canceled 
                // the operation.
                // Note that due to a race condition in 
                // the DoWork event handler, the Cancelled
                // flag may not have been set, even though
                // CancelAsync was called.
                resultLabel.Text = "Canceled";
            }
            else
            {
                // Finally, handle the case where the operation 
                // succeeded.
                resultLabel.Text = e.Result.ToString();
            }
 
            // Enable the UpDown control.
            this.numericUpDown1.Enabled = true;
 
            // Enable the Start button.
            startAsyncButton.Enabled = true;
 
            // Disable the Cancel button.
            cancelAsyncButton.Enabled = false;
        }
 
        // This event handler updates the progress bar.
        private void backgroundWorker1_ProgressChanged(object sender,
            ProgressChangedEventArgs e)
        {
            this.progressBar1.Value = e.ProgressPercentage;
        }
 
        // This is the method that does the actual work. For this
        // example, it computes a Fibonacci number and
        // reports progress as it does its work.
        long ComputeFibonacci(int n, BackgroundWorker worker, DoWorkEventArgs e)
        {
            // The parameter n must be >= 0 and <= 91.
            // Fib(n), with n > 91, overflows a long.
            if ((n < 0) || (n > 91))
            {
                throw new ArgumentException(
                    "value must be >= 0 and <= 91", "n");
            }
 
            long result = 0;
 
            // Abort the operation if the user has canceled.
            // Note that a call to CancelAsync may have set 
            // CancellationPending to true just after the
            // last invocation of this method exits, so this 
            // code will not have the opportunity to set the 
            // DoWorkEventArgs.Cancel flag to true. This means
            // that RunWorkerCompletedEventArgs.Cancelled will
            // not be set to true in your RunWorkerCompleted
            // event handler. This is a race condition.
 
            if (worker.CancellationPending)
            {   
                e.Cancel = true;
            }
            else
            {   
                if (n < 2)
                {   
                    result = 1;
                }
                else
                {   
                    result = ComputeFibonacci(n - 1, worker, e) + 
                             ComputeFibonacci(n - 2, worker, e);
                }
 
                // Report progress as a percentage of the total task.
                int percentComplete = 
                    (int)((float)n / (float)numberToCompute * 100);
                if (percentComplete > highestPercentageReached)
                {
                    highestPercentageReached = percentComplete;
                    worker.ReportProgress(percentComplete);
                }
            }
 
            return result;
        }
 
 
        #region Windows Form Designer generated code
        
        private void InitializeComponent()
        {
            this.numericUpDown1 = new System.Windows.Forms.NumericUpDown();
            this.startAsyncButton = new System.Windows.Forms.Button();
            this.cancelAsyncButton = new System.Windows.Forms.Button();
            this.resultLabel = new System.Windows.Forms.Label();
            this.progressBar1 = new System.Windows.Forms.ProgressBar();
            this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
            ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).BeginInit();
            this.SuspendLayout();
            // 
            // numericUpDown1
            // 
            this.numericUpDown1.Location = new System.Drawing.Point(16, 16);
            this.numericUpDown1.Maximum = new System.Decimal(new int[] {
            91,
            0,
            0,
            0});
            this.numericUpDown1.Minimum = new System.Decimal(new int[] {
            1,
            0,
            0,
            0});
            this.numericUpDown1.Name = "numericUpDown1";
            this.numericUpDown1.Size = new System.Drawing.Size(80, 20);
            this.numericUpDown1.TabIndex = 0;
            this.numericUpDown1.Value = new System.Decimal(new int[] {
            1,
            0,
            0,
            0});
            // 
            // startAsyncButton
            // 
            this.startAsyncButton.Location = new System.Drawing.Point(16, 72);
            this.startAsyncButton.Name = "startAsyncButton";
            this.startAsyncButton.Size = new System.Drawing.Size(120, 23);
            this.startAsyncButton.TabIndex = 1;
            this.startAsyncButton.Text = "Start Async";
            this.startAsyncButton.Click += new System.EventHandler(this.startAsyncButton_Click);
            // 
            // cancelAsyncButton
            // 
            this.cancelAsyncButton.Enabled = false;
            this.cancelAsyncButton.Location = new System.Drawing.Point(153, 72);
            this.cancelAsyncButton.Name = "cancelAsyncButton";
            this.cancelAsyncButton.Size = new System.Drawing.Size(119, 23);
            this.cancelAsyncButton.TabIndex = 2;
            this.cancelAsyncButton.Text = "Cancel Async";
            this.cancelAsyncButton.Click += new System.EventHandler(this.cancelAsyncButton_Click);
            // 
            // resultLabel
            // 
            this.resultLabel.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
            this.resultLabel.Location = new System.Drawing.Point(112, 16);
            this.resultLabel.Name = "resultLabel";
            this.resultLabel.Size = new System.Drawing.Size(160, 23);
            this.resultLabel.TabIndex = 3;
            this.resultLabel.Text = "(no result)";
            this.resultLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            // 
            // progressBar1
            // 
            this.progressBar1.Location = new System.Drawing.Point(18, 48);
            this.progressBar1.Name = "progressBar1";
            this.progressBar1.Size = new System.Drawing.Size(256, 8);
            this.progressBar1.Step = 2;
            this.progressBar1.TabIndex = 4;
            // 
            // backgroundWorker1
            // 
            this.backgroundWorker1.WorkerReportsProgress = true;
            this.backgroundWorker1.WorkerSupportsCancellation = true;
            // 
            // FibonacciForm
            // 
            this.ClientSize = new System.Drawing.Size(292, 118);
            this.Controls.Add(this.progressBar1);
            this.Controls.Add(this.resultLabel);
            this.Controls.Add(this.cancelAsyncButton);
            this.Controls.Add(this.startAsyncButton);
            this.Controls.Add(this.numericUpDown1);
            this.Name = "FibonacciForm";
            this.Text = "Fibonacci Calculator";
            ((System.ComponentModel.ISupportInitialize)(this.numericUpDown1)).EndInit();
            this.ResumeLayout(false);
 
        }
        #endregion
 
        [STAThread]
        static void Main()
        {
            Application.Run(new FibonacciForm());
        }
    }
}


Visual C++
  
#using <System.Drawing.dll>
#using <System.dll>
#using <System.Windows.Forms.dll>
 
using namespace System;
using namespace System::Collections;
using namespace System::ComponentModel;
using namespace System::Drawing;
using namespace System::Threading;
using namespace System::Windows::Forms;
 
public ref class FibonacciForm: public System::Windows::Forms::Form
{
private:
 
   int numberToCompute;
   int highestPercentageReached;
 
   System::Windows::Forms::NumericUpDown^ numericUpDown1;
   System::Windows::Forms::Button^ startAsyncButton;
   System::Windows::Forms::Button^ cancelAsyncButton;
   System::Windows::Forms::ProgressBar^ progressBar1;
   System::Windows::Forms::Label ^ resultLabel;
   System::ComponentModel::BackgroundWorker^ backgroundWorker1;
 
public:
   FibonacciForm()
   {
      InitializeComponent();
      numberToCompute = highestPercentageReached = 0;
      InitializeBackgoundWorker();
   }
 
 
private:
 
   // Set up the BackgroundWorker object by 
   // attaching event handlers. 
   void InitializeBackgoundWorker()
   {
      backgroundWorker1->DoWork += gcnew DoWorkEventHandler( this, &FibonacciForm::backgroundWorker1_DoWork );
      backgroundWorker1->RunWorkerCompleted += gcnew RunWorkerCompletedEventHandler( this, &FibonacciForm::backgroundWorker1_RunWorkerCompleted );
      backgroundWorker1->ProgressChanged += gcnew ProgressChangedEventHandler( this, &FibonacciForm::backgroundWorker1_ProgressChanged );
   }
 
   void startAsyncButton_Click( System::Object^ /*sender*/, System::EventArgs^ /*e*/ )
   {
 
      // Reset the text in the result label.
      resultLabel->Text = String::Empty;
 
      // Disable the UpDown control until 
      // the asynchronous operation is done.
      this->numericUpDown1->Enabled = false;
 
      // Disable the Start button until 
      // the asynchronous operation is done.
      this->startAsyncButton->Enabled = false;
 
      // Enable the Cancel button while 
      // the asynchronous operation runs.
      this->cancelAsyncButton->Enabled = true;
 
      // Get the value from the UpDown control.
      numberToCompute = (int)numericUpDown1->Value;
 
      // Reset the variable for percentage tracking.
      highestPercentageReached = 0;
 
      // Start the asynchronous operation.
      backgroundWorker1->RunWorkerAsync( numberToCompute );
   }
 
   void cancelAsyncButton_Click( System::Object^ /*sender*/, System::EventArgs^ /*e*/ )
   {  
      // Cancel the asynchronous operation.
      this->backgroundWorker1->CancelAsync();
 
      // Disable the Cancel button.
      cancelAsyncButton->Enabled = false;
   }
 
   // This event handler is where the actual,
   // potentially time-consuming work is done.
   void backgroundWorker1_DoWork( Object^ sender, DoWorkEventArgs^ e )
   {
      // Get the BackgroundWorker that raised this event.
      BackgroundWorker^ worker = dynamic_cast<BackgroundWorker^>(sender);
 
      // Assign the result of the computation
      // to the Result property of the DoWorkEventArgs
      // object. This is will be available to the 
      // RunWorkerCompleted eventhandler.
      e->Result = ComputeFibonacci( safe_cast<Int32>(e->Argument), worker, e );
   }
 
   // This event handler deals with the results of the
   // background operation.
   void backgroundWorker1_RunWorkerCompleted( Object^ /*sender*/, RunWorkerCompletedEventArgs^ e )
   {
      // First, handle the case where an exception was thrown.
      if ( e->Error != nullptr )
      {
         MessageBox::Show( e->Error->Message );
      }
      else
      if ( e->Cancelled )
      {
         // Next, handle the case where the user cancelled 
         // the operation.
         // Note that due to a race condition in 
         // the DoWork event handler, the Cancelled
         // flag may not have been set, even though
         // CancelAsync was called.
         resultLabel->Text = "Cancelled";
      }
      else
      {
         // Finally, handle the case where the operation 
         // succeeded.
         resultLabel->Text = e->Result->ToString();
      }
 
      // Enable the UpDown control.
      this->numericUpDown1->Enabled = true;
 
      // Enable the Start button.
      startAsyncButton->Enabled = true;
 
      // Disable the Cancel button.
      cancelAsyncButton->Enabled = false;
   }
 
   // This event handler updates the progress bar.
   void backgroundWorker1_ProgressChanged( Object^ /*sender*/, ProgressChangedEventArgs^ e )
   {
      this->progressBar1->Value = e->ProgressPercentage;
   }
 
   // This is the method that does the actual work. For this
   // example, it computes a Fibonacci number and
   // reports progress as it does its work.
   long ComputeFibonacci( int n, BackgroundWorker^ worker, DoWorkEventArgs ^ e )
   {
      // The parameter n must be >= 0 and <= 91.
      // Fib(n), with n > 91, overflows a long.
      if ( (n < 0) || (n > 91) )
      {
         throw gcnew ArgumentException( "value must be >= 0 and <= 91","n" );
      }
 
      long result = 0;
 
      // Abort the operation if the user has cancelled.
      // Note that a call to CancelAsync may have set 
      // CancellationPending to true just after the
      // last invocation of this method exits, so this 
      // code will not have the opportunity to set the 
      // DoWorkEventArgs.Cancel flag to true. This means
      // that RunWorkerCompletedEventArgs.Cancelled will
      // not be set to true in your RunWorkerCompleted
      // event handler. This is a race condition.
      if ( worker->CancellationPending )
      {
         e->Cancel = true;
      }
      else
      {
         if ( n < 2 )
         {
            result = 1;
         }
         else
         {
            result = ComputeFibonacci( n - 1, worker, e ) + ComputeFibonacci( n - 2, worker, e );
         }
 
         // Report progress as a percentage of the total task.
         int percentComplete = (int)((float)n / (float)numberToCompute * 100);
         if ( percentComplete > highestPercentageReached )
         {
            highestPercentageReached = percentComplete;
            worker->ReportProgress( percentComplete );
         }
      }
 
      return result;
   }
 
   void InitializeComponent()
   {
      this->numericUpDown1 = gcnew System::Windows::Forms::NumericUpDown;
      this->startAsyncButton = gcnew System::Windows::Forms::Button;
      this->cancelAsyncButton = gcnew System::Windows::Forms::Button;
      this->resultLabel = gcnew System::Windows::Forms::Label;
      this->progressBar1 = gcnew System::Windows::Forms::ProgressBar;
      this->backgroundWorker1 = gcnew System::ComponentModel::BackgroundWorker;
      (dynamic_cast<System::ComponentModel::ISupportInitialize^>(this->numericUpDown1))->BeginInit();
      this->SuspendLayout();
 
      // 
      // numericUpDown1
      // 
      this->numericUpDown1->Location = System::Drawing::Point( 16, 16 );
      array<Int32>^temp0 = {91,0,0,0};
      this->numericUpDown1->Maximum = System::Decimal( temp0 );
      array<Int32>^temp1 = {1,0,0,0};
      this->numericUpDown1->Minimum = System::Decimal( temp1 );
      this->numericUpDown1->Name = "numericUpDown1";
      this->numericUpDown1->Size = System::Drawing::Size( 80, 20 );
      this->numericUpDown1->TabIndex = 0;
      array<Int32>^temp2 = {1,0,0,0};
      this->numericUpDown1->Value = System::Decimal( temp2 );
 
      // 
      // startAsyncButton
      // 
      this->startAsyncButton->Location = System::Drawing::Point( 16, 72 );
      this->startAsyncButton->Name = "startAsyncButton";
      this->startAsyncButton->Size = System::Drawing::Size( 120, 23 );
      this->startAsyncButton->TabIndex = 1;
      this->startAsyncButton->Text = "Start Async";
      this->startAsyncButton->Click += gcnew System::EventHandler( this, &FibonacciForm::startAsyncButton_Click );
 
      // 
      // cancelAsyncButton
      // 
      this->cancelAsyncButton->Enabled = false;
      this->cancelAsyncButton->Location = System::Drawing::Point( 153, 72 );
      this->cancelAsyncButton->Name = "cancelAsyncButton";
      this->cancelAsyncButton->Size = System::Drawing::Size( 119, 23 );
      this->cancelAsyncButton->TabIndex = 2;
      this->cancelAsyncButton->Text = "Cancel Async";
      this->cancelAsyncButton->Click += gcnew System::EventHandler( this, &FibonacciForm::cancelAsyncButton_Click );
 
      // 
      // resultLabel
      // 
      this->resultLabel->BorderStyle = System::Windows::Forms::BorderStyle::Fixed3D;
      this->resultLabel->Location = System::Drawing::Point( 112, 16 );
      this->resultLabel->Name = "resultLabel";
      this->resultLabel->Size = System::Drawing::Size( 160, 23 );
      this->resultLabel->TabIndex = 3;
      this->resultLabel->Text = "(no result)";
      this->resultLabel->TextAlign = System::Drawing::ContentAlignment::MiddleCenter;
 
      // 
      // progressBar1
      // 
      this->progressBar1->Location = System::Drawing::Point( 18, 48 );
      this->progressBar1->Name = "progressBar1";
      this->progressBar1->Size = System::Drawing::Size( 256, 8 );
      this->progressBar1->Step = 2;
      this->progressBar1->TabIndex = 4;
 
      // 
      // backgroundWorker1
      // 
      this->backgroundWorker1->WorkerReportsProgress = true;
      this->backgroundWorker1->WorkerSupportsCancellation = true;
 
      // 
      // FibonacciForm
      // 
      this->ClientSize = System::Drawing::Size( 292, 118 );
      this->Controls->Add( this->progressBar1 );
      this->Controls->Add( this->resultLabel );
      this->Controls->Add( this->cancelAsyncButton );
      this->Controls->Add( this->startAsyncButton );
      this->Controls->Add( this->numericUpDown1 );
      this->Name = "FibonacciForm";
      this->Text = "Fibonacci Calculator";
      (dynamic_cast<System::ComponentModel::ISupportInitialize^>(this->numericUpDown1))->EndInit();
      this->ResumeLayout( false );
   }
};
 
[STAThread]
int main()
{
   Application::Run( gcnew FibonacciForm );
}