software solutions / project leadership / agile coaching and training

Hiding Thread.CurrentPrincipal from your code

Posted on April 13, 2009

You can get information about the current user who is logged in using Thread.CurrentPrincipal. The problem with this is that it’s difficult to work with it in tests. It forces you to set the current principal in your test setup so that your code will work correctly, and this can be difficult if not impossible in situations where you’re using Windows Authentication (if you’re using Forms Authentication, it’s not quite as painful, but it’s still a pain).

I don’t like to actually have calls to Thread.CurrentPrincipal scattered throughout my code. It makes my code less readable. Usually if I’m checking the principal, I want to know what user is logged in. That leads to code like this:

var currentUser = null;
var principal = Thread.CurrentPrincipal as MyCustomPrincipal;
if (principal != null)
currentUser = ((MyCustomPrincipal) Thread.CurrentPrincipal).User;

Ick. I don’t want to write this over and over throughout my code. What if I had a class called PrincipalFactory that dealt with everything having to do with the principal? My class could look like this:

public class PrincipalFactory : IPrincipalFactory
{
public MyCustomPrincipal GetCurrent()
{
return Thread.CurrentPrincipal as MyCustomPrincipal;
}

public User GetCurrentUser()
{
var principal = GetCurrent();
return (principal != null ? principal.User : null);
}

public void SetCurrentUser(User user)
{
Thread.CurrentPrincipal = new MyCustomPrincipal(user);
}
}

Now when I want to know who the current user is, I can write…

var currentUser = _principalFactory.GetCurrentUser();

Isn’t that much easier on the eyes?

It’s much easier to test too. I always use dependency injection and StructureMap, which also makes testing easier. Let’s say I had a class like this:

public class AccountController : Controller
{
private IPrincipalFactory _principalFactory;

public AccountController(IPrincipalFactory principalFactory)
{
_principalFactory = principalFactory;
}

[Authorize]
public ActionResult Index()
{
var model = new IndexViewModel();
model.WelcomeMessage = "Hello, " + _principalFactory.GetCurrentUser().Username;
return View(model);
}
}

In my test code, I’m going to use Rhino Mocks to stub out the IPrincipalFactory. So the test will essentially pretend that a user named “Jon” is the current user and then we’ll make sure that the Index() method does the right thing.

using System;
using NUnit.Framework;
using Rhino.Mocks;

[TestFixture]
public class When_displaying_the_index_view()
{
[Test]
public void Should_display_the_welcome_message_for_the_current_user()
{
// Arrange
var principalFactory = MockRepository.GenerateStub();
principalFactory.Stub(pf => pf.GetCurrentUser()).Return(new User { Username = "Jon" });

var controller = new AccountController(principalFactory);

// Act
controller.Index();

// Assert
Assert.IsTrue(((IndexViewModel)_controller.ViewData.Model).WelcomeMessage, Is.EqualTo("Welcome, Jon"));
}
}

This is much easier and cleaner than having to deal with Thread.CurrentPrincipal all over the place. If you didn’t hide Thread.CurrentPrincipal inside the PrincipalFactory class, you could still test it by setting Thread.CurrentPrincipal in the beginning of your test. I’ve been on projects that did it this way, and inevitably someone forgets to set Thread.CurrentPrincipal back to what it was before the test, or an exception happens and somehow the code that sets it back to the original value doesn’t run, and now tests will have different outcomes depending on what order you run them and which ones you run. This is usually a real pain to debug because you don’t know which test is causing the problem. Not fun.

4 Comments »

  1. Hiding Thread.CurrentPrincipal from your code…

    You’ve been kicked (a good thing) – Trackback from DotNetKicks.com…

    DotNetKicks.com — April 13, 2009 @ 8:28 pm

  2. [...] to VoteHiding Thread.CurrentPrincipal from your code (4/13/2009)Monday, April 13, 2009 from jonkruger.comYou can get information about the current user who is [...]

    ASP.NET MVC Archived Blog Posts, Page 1 — April 19, 2009 @ 10:47 pm

  3. Great work.

    Della — April 22, 2009 @ 6:15 am

  4. I want to listen good music!

    piskodrocho — July 10, 2009 @ 3:31 pm

Leave a comment





SERVICES
SOFTWARE SOLUTIONS
I have over 10 years of software development experience on several different platforms (mostly Ruby and .NET). I recognize that software is expensive, so I'm always trying to find ways to speed up the software development process, but at the same time remembering that high quality is essential to building software that stands the test of time.
PROJECT LEADERSHIP
I have experience leading and architecting large Agile software projects and coordinating all aspects of a project's lifecycle. Whether you're looking for technical expertise or someone to lead all aspects of an Agile project, I have proven experience from multiple projects in different environments that can help make your project a success.
AGILE COACHING
I believe that Agile processes and tools should be applied with common sense. I've spent the last 6 years working on Agile projects as a consultant in many different environments, both in leadership roles and as a practitioner doing the work. I can help you find out how Agile can work best in your organization, not just apply a prescriptive process.
TEST DRIVEN DEVELOPMENT TRAINING
TDD Boot Camp is a hands-on, three day, comprehensive training course that will teach you all of the skills, tools, frameworks that you will need to use test-driven development to develop real world .NET applications. If you're not looking for something that intensive, check out the the half-day version.
Have any questions? Contact me for more information.
PRESENTATIONS
The Business of You: 10 Steps For Running Your Career Like a Business
From CONDG 2012, Stir Trek 2014
From Stir Trek 2013, DogFoodCon 2013
From Stir Trek 2012, QA or the Highway 2014
(presented with Brandon Childers, Chris Hoover, Laurel Odronic, and Lan Bloch from IGS Energy) from Path to Agility 2012
(presented with Paul Bahler and Kevin Chivington from IGS Energy)
From CodeMash 2011
An idea of how to make JavaScript testable, presented at Stir Trek 2011. The world of JavaScript frameworks has changed greatly since then, but I still agree with the concepts.
A description of how test-driven development works along with some hands-on examples.
From CodeMash 2010
From CodeMash 2010