Daniel Vasquez Lopez

Friday, October 08, 2004

The ExecutionContext class in the .NET Framework 2.0

The following example shows a basic use of the new ExecutionContext class. This class allows you to capture the current context where the code is executing in (e.g. security, syncronization, call context, etc.)

If you use both ThreadPool.UnsafeQueueUserWorkItem and ThreadPool.UnsafeRegisterForWaitForSingleObject methods, you will notice that in your callback method you don't have access to a bunch of context data like the the security context. If you impersonate an User before calling any of the ThreadPool.Unsafe* methods, the identity that will use your callback method will be the process identity, not the impersonated one.

This example shows you how to access the impersonated identity from the callback executed by ThreadPoolUnsafeQueueUserWorkItem.

// Author: danielvl(removethis)@microsoft.com

using System;
using System.Text;
using System.Threading;
using System.Security.Principal;
using System.Runtime.InteropServices;
class Program
{
[DllImport("advapi32.dll")]
public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken);
static void Main(string[] args)
{
WindowsImpersonationContext ctxt = null;
try
{
// Impersonate other user
IntPtr userToken;
LogonUser("SimpleUser", "MyLocalMachine", "T.hisIsMy.Secret0", 2, 0, out userToken);
// At this point I am MyDomain\danielvl
ctxt = WindowsIdentity.Impersonate(userToken);
// At this point I am MyLocalMachine\SimpleUser
// Save my current context (MyLocalMachine\SimpleUser)
ExecutionContext savedContext = ExecutionContext.Capture();
// Call the unsafe version of ThreadPool.QueueUserWorkItem
ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(MyUserWorkItem), savedContext);
}
finally
{
// Revert identity to MyDomain\danielvl
if (ctxt != null)
ctxt.Undo();
}
Console.Read();
}
///


/// Method invoked from ThreadPool.UnsafeQueueUserWorkItem
///

static void MyUserWorkItem(object state)
{
// Restore the ExecutionContext object
ExecutionContext context = (ExecutionContext)state;
// Get the curren username where ThreadPool.UnsafeQueueUserWorkItem is executing
string userNameFromUnsafeContext = WindowsIdentity.GetCurrent().Name;
// Execute myContextCallbackHandler in the context saved
ExecutionContext.Run(context.CreateCopy(), myContextCallbackHandler, userNameFromUnsafeContext);
}
///
/// The handler to the ContextCallback delegate
///

static ContextCallback myContextCallbackHandler = new ContextCallback(MyContextCallback);
///
/// Method invoked from ExecutionContext.Run
///

static void MyContextCallback(object state)
{
string userNameFromUnsafeContext = (string)state;
string userNameFormSavedContext = WindowsIdentity.GetCurrent().Name;
Console.WriteLine("Username from unsafe context is {0}", userNameFromUnsafeContext);
Console.WriteLine("Username from context saved is {0}", userNameFormSavedContext);
}
}

- Output -
Username from unsafe context is MyDomain\danielvl
Username from context saved is MyLocalMachine\SimpleUser