For Geeks: Skip explanations, just show the solution!
Well, many of us already utilize this pattern – just without knowing it has a name. I found this name somewhere, and I like it.
On http://aabs.wordpress.com the Intend is defined like this:
Intent: Provide a place to store scope or context related information or functionality that automatically follows the flow of execution between execution scopes or domains.
Read more about the pattern here: http://aabs.wordpress.com/2007/12/31/the-ambient-context-design-pattern-in-net/
.NET uses often as for example in System.Transactions.TransactionScope or System.Web.HttpContext.
While TransactionScope is saved per thread using [ThreadLocal], HttpContext is sometimes spans multiple threads following the flow of a full request execution – which can be asynchronous.
Example
The new Library System.Transactions offers generic transaction handling to your Application. Every method called within that scope can now join the running transaction, so does Ado.NET.
using(var t = new TransactionScope()) { // do something with for example ADO.Net t.Complete(); }Why do they use the using-statement here?
LocalDataStoreSlot and [ThreadStatic]-Attribute
In many cases we just want to let the context be known within specific execution scope within one thread.
In .NET Framework 1.1 you had to use the LocalDataStoreSlot to store Data on a running Thread.
LocalDataStoreSlot slot = Thread.AllocateDataSlot(); Thread.SetData(slot, "my value"); string x = (string)Thread.GetData(slot);In v2.0 Microsoft added the [ThreadStatic] attribute. Utilizing this class a static field can be turned into a thread static field, which holds the value just in the thread it was set in.
[ThreadStatic] private static string myContext; public void DoSomething() { myContext = "value"; DoSomethingElse(); /* if DoSomethingElse() would be * called by another thread now * the current value would be null. */ myContext = null; } public void DoSomethingElse() { Console.WriteLine("Current value: " + myContext); }The Problem
If you don’t clean up, your bits may stay in the thread “forever”, even if it goes back to the thread pool! The next enqueued work item will find it there. Even worse in asp.net, where data could suddenly be shared between different requests using the same thread.
With a try..finally or making a helper class that implements IDisposable and cleans up on Dispose you can avoid these problems.
If you have nested scopes, the outer scope should be recovered, after the inner one has been closed, right?
The Solution
I created a class named ThreadVariable<T> which behaves pretty much like a static field marked as a [ThreadStatic]. But instead of assigning a value directly, a value is always only valid within a specific scope.
public static readonly ThreadVariable<string> myContext = new ThreadVariable<string>(); public void DoSomething() { using(myContext.Use("value")) { DoSomethingElse(); /* if DoSomethingElse() would be * called by another thread now * the current value would be empty. */ } // the value is not available anymore } public void DoSomethingElse() { Console.WriteLine("Current value: " + myContext.Value); }
Grab the bits and feel free to copy what you need:
ThreadVariable Source and Tests (VS 2008) (Zip, 40k)
Update: Is now available as Minimod from Nuget or Github.Features:
- Allows nested scopes. Protects from messing up the values by disposing scopes wrongly.
- The Property Current will throw an InvalidOperationException if you try to access it from the outside of a scope. This helps preventing NullReferenceExeptions
- CurrentOrDefault will return the value within the current scope, or if it isn’t available, default(T).
This is nice, if you want to use the coalescing operator ??:
(for example: return threadVar.CurrentOrDefault ?? “another value”;) - In the constructor you can pass a fallback value. This will then always be returned on Current and on CurrentOrDefault, even if no value is available in the calling context.
- HasCurrent indicates wether there is a value available. Note: is always true, if a fallback value is present.
More Examples
Some times you just want to make some information publicly available. It’s doesn’t have to be secure, it’s all your code. So what!
public static class SomeThreadVars { public static readonly ThreadVariable<bool> IsSuperUser = new ThreadVariable<bool>(false); } // now you can use it whereever you want using(SomeThreadVars.IsSuperUser.Use(true)) { bool isSu = SomeThreadVars.IsSuperUser.Current; }But especially if you give a scope super user rights, you should prevent that anyone just sets the value as they want. Still, you need it to be accessible publicly.
public class UserContext { private static readonly ThreadVariable<bool> isSuperUser = new ThreadVariable<bool>(false); public static bool IsSuperUser { get { return isSuperUser.Current; } } public static IDisposable EnterSuperUserScope(string passkey) { if (passkey != "supersecure" ) throw new InvalidCredentialException( "The passkey you used is wrong!"); return isSuperUser.Use(true); } } public class BusinessObject { public static bool DeleteDataBase() { if (!UserContext.IsSuperUser && !Thread.CurrentPrincipal.IsInRole( "canDeleteDataBase")) throw new AccessViolationException("go home!"); // delete the database return true; } }Now you’ve got a secure wrapper around your context, which also can be used from the outside – but controlled.
using (UserContext.EnterSuperUserScope("supersecure")) { BusinessObject.DeleteDataBase(); // works perfectly }
Hey, thanks for the reply to my MS forum post–I have trouble posting on there so thought it’d be easier to thank you here.
Neat article; it’s always fun to push the limits of what Microsoft intended for the “typical” user. I think I understand roughly what you’re doing, but it’s not exactly what I needed, which was a non-static (i.e. instance-based) thread-local variable, which as far as I know (haven’t done much testing yet) I’ve been able to solve rather simply by just using a dictionary keyed by a Thread. (e.g. return myDictionary[Thread.CurrentThread]; )
I do like the bit on scopes you added, and as you mention this could be very handy for granting permissions and such, and will keep it in mind when I get around to the security aspect of my little platform.
Logan
Hi,
you could just drop the static-keyword, and it should work per instance + per thread, too.
It saves to the thread per instance of the ThreadVariable. You can choose yourself if and how to share this instance.
I’ll have a look on FeadBeast. If I like it, I’ll blog it 😉
Lars
Pls do. I’m working on the next version right now and it’s going to be a significant improvement. 😉
Thanks for the note–I wasn’t sure if your code would work on an instance level. If I have trouble with my naive implementation I will look to yours for inspiration.
Pingback: How to make ASP.net session state testable « .Net Braindrops
Hi larscorneliussen,
I like your coding plug in!! Where u get it?
Regards
It is a wordpress plugin:
They utilize the google syntax highlighter:
http://code.google.com/p/syntaxhighlighter
I also wrote a WLW Plugin that helps me posting the code – WLW does not handle correctly 😉
Where i can get this wordpress plugin ? What’s the plugin name? I want to use it for my wordpress blog 🙂
It’s just a wordpress.org – macro. I don’t know if it is available as plugin somewhere.
http://faq.wordpress.com/2007/09/03/how-do-i-post-source-code/
Hmmm… Surely ASP thread agility breaks this in a web app?
http://piers7.blogspot.com/2005/11/threadstatic-callcontext-and_02.html
It is possible for ASP.Net to swap threads on you mid request making your [ThreadStatic] “values” member unreliable.
Thoughts?
Youre right!! The implementation does not fit web applications.
Usually I wrap the HttpContext.Items as well as HttpContext.Application in a similar manner as I described for a typed SessionState.
Look at my second comment there, too.
https://startbigthinksmall.wordpress.com/2008/05/14/how-to-wrap-the-aspnet-session-state/
So… If TransactionScope uses [ThreadStatic] then that too is unsuitable to use from ASP.Net?
This would seem to be proved by its Dispose method which checks “scopeThread != Thread.CurrentThread”.
What’s the alternative?
Putting a TransactionScope into a web aware ambient context?
The thread wont switch within on method excecution.
using (IDisposable)
{
// the thread wont just switch while this executes.
}
But the thread may switch between your request handling within your IHttpModule and your Page or IHttpHandler or in case of asynchronous requests. Then you have to use System.Web.HttpContext.Current.Items wich is ment to transfer data from modules to handlers.
While executing one single Method you can safely use transactions or my implementation of the ambient context pattern.
Thats at least how I understand it 🙂
I removed the fallback, added a protected T CreateInstance() method that throws the InvalidOperationException, and call the CreateInstance method from a new Use() method so a derived ThreadVariable can act as a factory, and scope and object creation can be done in a single call.
Pingback: The Ambient Context Pattern
Sure!
It is now available as minimo from Nuget Gallery here:
ThreadVariable Minimo (Source Included)
Originating Source is found on github: https://github.com/minimod/minimods/tree/master/MiniMods/ThreadVariable
Is there a chance you could share the source for this implementation again?