Hiding Thread.CurrentPrincipal from your code
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.
Great work.
I want to listen good music!