cat opening-doors.md

Opening Doors

Nov 04, 2008

joshka left a comment on my previous post that reads…

Can you talk about the Application Context and IKey stuff a little in a future post?

The IKey<T> interface defines a contract for different keys that are put into a dictionary. It depends on the implementation of the key to know how to parse its value out of the dictionary.

  public interface IKey<T>
  {
      bool is_found_in(IDictionary items);
      T parse_from(IDictionary items);
      void remove_from(IDictionary items);
      void add_value_to(IDictionary items, T value);
  }

An implementation of the key that we used for shoving an ISession into the HttpContext.Items collection is the TypedKey<T>. It creates a unique key based on type T.

  internal class TypedKey<T> : IKey<T>
  {
      public bool is_found_in(IDictionary items)
      {
          return items.Contains(create_unique_key());
      }

      public T parse_from(IDictionary items)
      {
          return (T) items[create_unique_key()];
      }

      public void remove_from(IDictionary items)
      {
          if (is_found_in(items))
          {
              items.Remove(create_unique_key());
          }
      }

      public void add_value_to(IDictionary items, T value)
      {
          items[create_unique_key()] = value;
      }

      public bool Equals(TypedKey<T> obj)
      {
          return !ReferenceEquals(null, obj);
      }

      public override bool Equals(object obj)
      {
          if (ReferenceEquals(null, obj)) return false;
          if (ReferenceEquals(this, obj)) return true;
          if (obj.GetType() != typeof (TypedKey<T>)) return false;
          return Equals((TypedKey<T>) obj);
      }

      public override int GetHashCode()
      {
          return GetType().GetHashCode();
      }

      private string create_unique_key()
      {
          return GetType().FullName;
      }
    }

It knows how to add a value into the dictionary using it as the key, and how to parse values from the dictionary using it. The application context can be an adapter around the HttpContext, or a hand rolled context for win forms. An implementation on the web might look like….

  public class WebContext : IApplicationContext
  {
      public bool contains<T>(IKey<T> key)
      {
          return key.is_found_in(HttpContext.Current.Items);
      }

      public void add<T>(IKey<T> key, T value)
      {
          key.add_value_to(HttpContext.Current.Items, value);
      }

      public T get_value_for<T>(IKey<T> key)
      {
          return key.parse_from(HttpContext.Current.Items);
      }

      public void remove(IKey<ISession> key)
      {
          key.remove_from(HttpContext.Current.Items);
      }
  }

When running your integration tests, you can swap out the implementation with an implementation specific to running unit tests.