Free .Net Ambient Context Pattern Implementation

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

Continue reading

Advertisement

Using the using-statement

“Using statement?”, you may ask. “What is so interesting about that? I use it every day importing tons of namespaces!”

Well, i mean the other using statement; that one that results in a nice try..finally in IL, without having to write lots of code.

Well lets say you want to access a file, a database, or whatever resource that needs to be closed after usage:

StreamReader sr = new StreamReader(@"c:\mytextfile.txt");
sr.ReadToEnd().Count(); // just doing something
sr.Close(); // closing a resource explicitly. gooood!
The problem here is: If the file for example is not encoded correctly, or you’re just doing something inbetween opening and closing your reader that might fail, you’re resource will not be closed until the GC disposes it. This in some cases might mean, until your application is closed.
Putting a try catch arround it helps:
StreamReader sr = null;
try
{
  sr = new StreamReader(@"c:\mytextfile.txt");
  sr.ReadToEnd().Count(); // just doing something
}
finally
{
  if (sr != null) // StreamReader.ctr() could fail...
  sr.Close();
}

The using statement does exactly the same. The IL-Code also looks pretty similar, but it is way easier to write.

using(StreamReader sr = new StreamReader(@"c:\my.txt"))
{
  sr.ReadToEnd().Count(); // just doing something
}
The using-statement takes any object implementing IDisposable. In the end or in case of any error, it will safely dispose the used resource. The Dispose()-Method on Streams or any other Reader/Writer in usually does the same thing as Close() does.
You can even nest them if you have to use multiple resource at once:
using(StreamReader sr1 = new StreamReader(@"c:\my1.txt"))
using (StreamReader sr2 = new StreamReader(@"c:\my2.txt"))
using (StreamWriter sw = new StreamWriter(@"c:\mynew.txt"))
{
  sw.WriteLine(sr1.ReadToEnd());
  sw.WriteLine(sr2.ReadToEnd());
}

Almost any resource usage in .Net, for example ADO.Net implements the IDisposable on their classes. The connection will be closed and disposed, the transaction will be rolled back if something fails before commit.

using (var conn = new SqlConnection("..."))
{
  using (var st = conn.BeginTransaction())  
  {
    conn.Open();
  var sc = conn.CreateCommand();
    sc.CommandText = "UPDATE ...";
    sc.ExecuteNonQuery();
  var sc2 = conn.CreateCommand();
    sc2.CommandText = "SELECT ...";
    using (var reader = sc2.ExecuteReader())
  {
  return reader.GetString(0);
  }
  st.Commit();
  }
}

Have fun!

Note:There is no guarantee, that IDisposable.Dispose() on classes you find in .NET or other libraries will close everything as necessary. On the WCF clients, for instance, you need to call Abort() instead of Close() or Dispose() in case of an communication error, otherwise your connection will stay opened.

If you’re in doubt on a certain class, just use Reflector to check its behaviour.

Updated: Other Resources

kick it on DotNetKicks.com

Still learning?

“Start big, think small” – that’s what we usually do, right? We, as programmers, usually just are too certain about our way to solve problems.
“Think big, start small, grow fast!”. Start criticizing yourself. Start thinking that there might be anyone else out there who has found a better solution. Learn from him.

You all know about the “my baby-problem”. One team member lately said: “I love my baby so much, that I want it to look nicer”. Well, at least for developers, this is a good mind.

Some articles I like:

http://codeclimber.net.nz/archive/2008/04/02/Self-criticism-is-the-key-to-success.aspx
http://itscommonsensestupid.blogspot.com/2008/03/programming-is-all-about-passion.html