In most applications you usually store and cache some user information in a session object. Most actions are dependent on this information, which means that many services require this information. This problem can be solved using different approaches. What I usually end up with is creating a user ticket class which holds maybe a subset of the user information (or the complete user class) and other session specific information. The simplest approach is then to pass this object along to each service / method that needs it:

public class WishListService
{
  private IWishListRepository wishListRepository;

  public WishListService(IWishListRepository wishListRepository)
  {
    this.wishListRepository = wishListRepository;
  }

  public void AddToWishList(IUserTicket ticket, Product product)
  {
    // handle all the important stuff
  }
}

The problem with this approach is that all callers need to fetch the user ticket. If you have deep method stacks and the deepest component needs the session information then all methods needs to pass the object along.

A sometimes nicer approach is to let the components fetch the session information on their own (through an interface):

public class WishListService
{
  private IWishListRepository wishListRepository;
  private ITicketAccessor ticketAccessor;

  public WishListService(IWishListRepository wishListRepository, ITicketAccessor ticketAccessor)
  {
    this.wishListRepository = wishListRepository;
    this.ticketAccessor = ticketAccessor;
  }

  public void AddToWishList(Product product)
  {
    IUserTicket ticket = ticketAccessor.Current();
    // handle all the important stuff
  }
}

This approach makes the component easier to use and the method calls are simpler, dependencies to the session (ticket) information is handled by the ITicketAccessor which can be inject by a IoC container.

Another approach is to have a static RuntimeContext class which static properties to access the session information from anywhere in your application:

public class RuntimeContext
{
  private const string KEY_TICKET = "RuntimeContext.Ticket";        

  /// <summary>
  /// Used to access the ticket for the current request
  /// </summary>
  public static IUserTicket Ticket
  {
    get
    {
      // try local execution context first
      IUserTicket ticket = Local.Data[KEY_TICKET] as IUserTicket;
      if (ticket != null)
        return ticket;

      // try session
      if (Local.RunningInWeb && HttpContext.Current.Session != null)
      {
        ticket = HttpContext.Current.Session[KEY_TICKET] as IUserTicket;
        // cache in local 
        if (ticket != null)
          Local.Data[KEY_TICKET] = ticket;
      }

      return ticket;
    }
    set
    {
      Local.Data[KEY_TICKET] = value;

      // store in session if running in web 
      if (Local.RunningInWeb)
      {
        HttpContext.Current.Session[KEY_TICKET] = value;
      }
    }
  }
}

The Local class in the above code is an abstraction over HttpContext.Current.Items and Thread data depending on if the code is being run in web context or not. This last approach is very easy to work with but you have less control over where and how the data is accessed.

There is also Thread.CurrentPrincipal which is a good to use, especially for user authorization. I am not sure which of the approaches I like more, the second one is probably the best one from a purist / TDD point of view. I will post a question in the ALT.NET mailing list to find out what solutions smarter people than me have arrived at.

0 comments: