in·dom·i·ta·ble
adj.
Incapable of being overcome, subdued, or vanquished; unconquerable.
4th
MAY
Nashville Alt.Net Lunch and Learn, June 3 : Scott Walters presents “Mass Transit”
Posted by indomitablehef | Filed under Alt.Net
The next Nashville Alt.Net Lunch and Learn will be on Wednesday, June 3, at 11:30…same location as last time
Scott Walters will present on “Mass Transit“:
MassTransit is lean service bus implementation for building loosely coupled applications using the .NET framework. ( http://code.google.com/p/masstransit/ )
8th
APR
Javascript for Grown-Ups: Setting up the DOM
Posted by indomitablehef | Filed under jQuery, qUnit, TDD
When testing javascript and jQuery code, I find I’m often adding elements here and there to the DOM, usually appending to a div. In such cases, I try to write my functions such that I pass in the container div as a selector. For example:
function AddToyToBox(toy, box) { var toyId = toy.Name.replace(/ /g, ''); //remove spaces from the name $('<div id="' + toyId + '"></div>').addClass('toy').appendTo(box); }
In this trivial example, we’re taking a “toy” object, creating a div for it, and adding it to some element in the DOM that represents a “box”, probably another div.
The qUnit test for this method, then, looks like this: (using my custom Assertions, described here)
test("Can Add Toy to ToyBox", function() { var toy = new Toy('Monster Truck'); var expectedToyBoxHtml = "<div class=\"toy\" id=\"MonsterTruck\"></div>"; AddToyToBox(toy, '#stubToyBoxDiv'); Assert.AreEqual(expectedToyBoxHtml, $('#stubToyBoxDiv').html()); });
Notice the reference to #stubToyBoxDiv. In my tests.html file, I was putting some “stub” html at into a div at the bottom of the file, so that I would have a container to drop my elements into when testing methods like AddToToBox(). I even had a clever way to clean up after myself after I was done - I made my last test remove the div that contained all my stub container divs. This quickly became a pain, however, because I found myself needing to have #stubToyBoxDiv1, #stubToyBoxDiv2, etc.
But thanks to jQuery, there is a much better and more elegant way to do this than littering up your tests.html file with stub divs. Instead, just create the dom element you need as part of your test setup, and remove it when you’re done:
test("Can Add Toy to ToyBox", function() { var toy = new Toy('Monster Truck'); var expectedToyBoxHtml = "<div class=\"toy\" id=\"MonsterTruck\"></div>"; $('<div id="stubToyBoxDiv"/>').appendTo('body'); AddToyToBox(toy, '#stubToyBoxDiv'); Assert.AreEqual(expectedToyBoxHtml, $('#stubToyBoxDiv').html()); $('#stubToyBoxDiv').remove(); });
I added the following DOMSetup and DOMTeardown methods, for better test readability:
DOMSetup = function(element, container) { var el = $(element); if (container != null) el.appendTo(container); else el.appendTo('body'); } DOMTearDown = function(selector) { $(selector).remove(); }
So now my test can look like this:
test("Can Add Toy to ToyBox", function() { var toy = new Toy('Monster Truck'); var expectedToyBoxHtml = "<div id=\"MonsterTruck\" class=\"toy\"></div>"; DOMSetup('<div id="stubToyBoxDiv"/>'); AddToyToBox(toy, '#stubToyBoxDiv'); Assert.AreEqual(expectedToyBoxHtml, $('#stubToyBoxDiv').html()); DOMTearDown('#stubToyBoxDiv'); });
7th
APR
Javascript for Grown-Ups: an Assertion Helper for qUnit
Posted by indomitablehef | Filed under jQuery, qUnit, TDD
In an effort to write my jQuery and Javascript code with the same rigor I use when writing my c# and even Sql code, I’ve started using the qUnit testing framework. qUnit is the unit testrunner for the jQuery project.
So far, I’m loving it, with a only few caveats. For one, I would like to write more BDD-style tests, and though I can sort of do it, it’s not very expressive. At some point, I’m going to want to try out JSpec, but for now I’m going to keep on working with qUnit.
Antother issue is that I don’t find it very expressive. For example, the AssertAreEqual function is called just “equals(actual, expected)”, and the AssertIsTrue method is just “ok(actual, expected)”. I miss my Assert.AreEqual and Asssert.IsTrue expressiveness, and I don’t like having “actual” come before “expected” in the parameter list.
So, I wrote this little AssertionHelper to help make my tests more expressive:
function AssertionHelper() { this.IsTrue = function(bool, message) { ok(bool,message); }; this.IsFalse = function(bool, message) { ok(!bool,message); }; this.AreEqual = function(expected, actual, message) { equals(actual, expected, message); }; this.AreNotEqual = function(expected, actual, message) { ok(actual != expected, message); }; this.AreSame = function(expected, actual, message) { same(actual, expected, message); } }
Now, in my tests.js file, I can just declare a variable called Assert as a new AssertionHelper, and use it in my tests to get the familiar expressiveness and semantics of the xUnit family of testing frameworks.
var Assert = new AssertionHelper(); $(document).ready(function() { test("a basic test example", function() { // instead of: ok(true, "this test is fine"); //use Assert.IsTrue(true); Assert.IsTrue(true, "this test is fine"); Assert.IsFalse(false); Assert.IsFalse(false, "this test is fine"); var value = "hello"; //instead of: equals("hello", value, "We expect value to be hello"); //use Assert.AreEqual(value, "hello"); Assert.AreEqual(value, "hello", "We expect value to be hello"); Assert.AreNotEqual(value, "goodbye"); Assert.AreNotEqual(value, "goodbye", "We expect value to be hello"); Assert.AreNotEqual(value, "hello"); Assert.AreNotEqual(value, "hello", "this test and the one before it should fail"); var x = { "name": "myobject" }; var y = x; var z = { "name": "myobject2" }; Assert.AreSame(y, x); Assert.AreSame(y, x, "these two should be the same"); Assert.AreSame(z, x, "this test should fail"); }); });
UPDATE: Reader ToneD shared the following improvement in the comments. He’s using a static class, which negates the need for instantiation and gives you intellisense on the Assert methods:
Assert = { IsTrue: function(bool, message) { ok(bool, message); }, IsFalse: function(bool, message) { ok(!bool, message); }, AreEqual: function(expected, actual, message) { equals(actual, expected, message); }, AreNotEqual: function(expected, actual, message) { ok(actual != expected, message); }, AreSame: function(expected, actual, message) { same(actual, expected, message); } }
30th
MAR
Speaking at DevLink 2009
Posted by indomitablehef | Filed under DevLink, Asp.Net MVC

The session list for DevLink 2009 is in, and I’m doing two sessions:
Asp.Net MVC : Patterns and AntiPatterns
ASP.NET MVC is Microsoft’s newest framework for building web applications. As with any new technology offering, we’ve begun to see a new set of best (and worst) practices emerging. In this in-depth session, we’ll go beyond the basics of how MVC works and look deeper into things you can do but shouldn’t, as well as some proven strategies for building scalable, maintainable, loosely coupled and easily testable ASP.Net MVC applications.
Multi-Tenancy: Beyond the whiteboard
With Multi-Tenancy and SaaS being among the hottest topics in software development, there’s no shortage of information available on maturity models, commercial SaaS platforms, and data partitioning patterns. Try to find some example code, however, and you’re likely to come up frustrated and empty-handed. In this in-depth session, we’ll go beyond the high-level discussions of maturity models and vendor sales pitches and dig into some concrete code examples and design patterns for implementing multi-tenant web applications in .Net. With examples in C#, ASP.Net, LinqToSql, ASP.Net MVC, TSQL, and NHibernate.
25th
MAR
Exploring MvcContrib: TestControllerBuilder
Posted by indomitablehef | Filed under Asp.Net MVC, TDD
The MvcContrib project on codeplex is “a series of assemblies that add functionality to Microsoft’s ASP.NET MVC Framework and make the framework easier to use”. One of the areas I’ve found immediately useful is the TestHelper library.
Let’s take a deeper look into this library, starting with the TestControllerBuilder.
One of the many things that the Asp.Net Mvc Framework has going for it is that it is easier to test. Even so, when you’re dealing with HttpContext, Request, Response, Form, QueryString and such, it can still be very difficult to isolate all the things you need isolate, mock all the things you need to mock, and get access to internal collections like Form, QueryString, and Session. The TestControllerBuilder gives us a test-specific ControllerFactory that we can use to initialize our controllers for testing, and gives us access to those internal collections.
To set up our “PatientController” for testing using the TestControllerBuilder, we create a PatientController and a TestControllerBuilder and call “InitializeController”, like this:
[TestFixture]
public class PatientControllerTest
{
private PatientController controller;
private TestControllerBuilder controllerBuilder;
[SetUp]
public void Setup()
{
controller = new PatientController();
controllerBuilder = new TestControllerBuilder();
controllerBuilder.InitializeController(controller);
}
<...>Imagine that we are storing some data about the current state of this Patient in the Session - for example, “Admitted”, “Triage”, “ER”, etc. And imagine that we are grabbing that state information from the Form collection directly. (There are certainly many better ways to do this, but bear with me for the sake of this contrived example). We need to test to make sure that when the state is passed in as a Form variable, after the controller action is completed, the Session variable for PatientState is set properly.
Having set up our controller using the TestControllerBuilder, we can now write a test like this:
[Test]
public void PatientStateInFormVariableShouldSetPatientStateInSessionVariable()
{
controllerBuilder.Form["PatientState"] = "Admitted";
controller.SetState();
controller.HttpContext.Session["PatientState"].ShouldEqual("Admitted", "");
}Pretty good test, right? But it looks a little too much like magic for me to just copy and paste it and move on, so let’s dig into how the TestControllerBuilder does this magic.
Notice that the Form collection we added to was the controllerBuilder.Form collection, and that the HttpContext we checked for our session variable was controller.HttpContext. Obviously this isn’t a real HttpContext, so let’s see where it comes from. If we pull down the source code for MvcContrib and look at the TestControllerBuilder.cs class in the MvcContrib.TestHelper project, it becomes much clearer.
The TestControllerBuilder has public properties for HttpContext, Session, and Form, like so:
<...> /// <summary> /// Gets the HttpContext that built controllers will have set internally when created with InitializeController /// </summary> /// <value>The HTTPContext</value> public HttpContextBase HttpContext { get; protected set; } <...> /// <summary> /// Gets the Form data that built controllers will have set internally when created with InitializeController /// </summary> /// <value>The NameValueCollection Form</value> public NameValueCollection Form { get; protected set; } <...> /// <summary> /// Gets the Session that built controllers will have set internally when created with InitializeController /// </summary> /// <value>The IHttpSessionState Session</value> public HttpSessionStateBase Session { get; protected set; } <...>
The Constructor for TestControllerBuilder calls a protected method called SetupHttpContext, which creates mock objects for the HttpContext, Request, Response and Server objects, like so:
protected void SetupHttpContext() { HttpContext = _mocks.DynamicMock<HttpContextBase>(); var request = _mocks.DynamicMock<HttpRequestBase>(); var response = _mocks.DynamicMock<HttpResponseBase>(); var server = _mocks.DynamicMock<HttpServerUtilityBase>(); _cache = HttpRuntime.Cache; SetupResult.For(HttpContext.Request).Return(request); SetupResult.For(HttpContext.Response).Return(response); SetupResult.For(HttpContext.Session).Return(Session); SetupResult.For(HttpContext.Server).Return(server); SetupResult.For(HttpContext.Cache).Return(_cache); QueryString = new NameValueCollection(); SetupResult.For(request.QueryString).Return(QueryString); Form = new NameValueCollection(); SetupResult.For(request.Form).Return(Form);
Notice that the public property HttpContext is a mock object, and the result of requesting HttpContext.Request is set up so that it will return a mocked HttpRequestBase object as well. Notice also that we’ve setup the result for calls to HttpContext.Session to return the TestControllerBuilder’s public Session property.
Taking it to the next step down, we see that calling HttpContext.Request.Form will return the public property Form, which is just a NameValueCollection. It’s worth noting again here that the Form, QueryString, and Session objects we will get from our mocked HttpContext object are not mock objects but “stubbed” objects - public properties of the TestControllerBuilder class.
Now, to wire these mocked and stubbed objects up so that our controller can use them when we are testing it, we call the TestControllerBuilder’s InitializeController method, and pass it our controller. InitializeController looks like this:
/// <summary> /// Creates the controller with proper environment variables setup. /// </summary> /// <param name="controller">The controller to initialize</param> public void InitializeController(Controller controller) { var controllerContext = new ControllerContext(HttpContext, RouteData, controller); controller.ControllerContext = controllerContext; controller.TempData = TempDataDictionary; }
Here we create a new ControllerContext, and pass in the Mocked-up and Stubbed-up HttpContext object that was set up by the constructor call to SetUpHttpContext(), and set the controllerContext on our controller to that new ControllerContext.
So, when we set the form variable:
controllerBuilder.Form["PatientState"] = "Admitted";
…and our controller’s SetState() method calls some code that looks something like this:
Session["PatientState"] = Request.Form["PatientState"];
… When our controller attempts to access the value at Request.Form, the Form object it is getting is the NameValueCollection property called “Form” from the TestControllerBuilder that was used to initialize the ControllerContext for our controller.
Here is the relevant code from the TestControllerBuilder’s protected SetUpHttpContext method:
HttpContext = _mocks.DynamicMock<HttpContextBase>(); var request = _mocks.DynamicMock<HttpRequestBase>(); <...> SetupResult.For(HttpContext.Request).Return(request); <...> Form = new NameValueCollection(); SetupResult.For(request.Form).Return(Form);
In our test, when we call:
controller.HttpContext.Session["PatientState"].ShouldEqual("Admitted", "");
The session collection we are getting is the public HttpSessionStateBase property of the TestControllerBuilder called “Session”, which was set up to be the result of any calls to HttpContext.Session in our mocked HttpContext.
So, that’s the TestControllerBuilder - an easy way to test your controllers and get access to stubs of all those internal collections based on HttpContext that you could never get to in order to test before. Next time, we’ll take a look at the TestHelper project’s extension methods that allow you to examine the return values of your controller actions, and what parameters were passed to ReturnView, RedirectToAction, etc.
9th
MAR
Forms Authentication in Asp.Net MVC, Part IV
Posted by indomitablehef | Filed under Asp.Net MVC
This is part 4 of 4
Forms Authentication in Asp.Net MVC
In Parts I, II, and III, you may have noticed constructors in my classes that look like this:
public class MembershipController: Controller { private readonly IAuthenticationProvider authenticationProvider; private readonly IMembershipProvider membershipProvider; public MembershipController(IAuthenticationProvider authenticationProvider, IMembershipProvider membershipProvider) { this.authenticationProvider = authenticationProvider; this.membershipProvider = membershipProvider; } public MembershipController():this(ServiceLocator.Current.GetInstance<IAuthenticationProvider>(), ServiceLocator.Current.GetInstance<IMembershipProvider>()) {} <...>
So what’s all that “ServiceLocator” stuff? That’s a hook int our Inversion of Control container, which happens to be Castle Windsor. If you’re not familiar with IoC, I suggest you check out these dimecasts on the subject. Getting into all the details is outside the scope of this series, but I will show you how to hook it up in Asp.Net MVC.
We’re also using the CommonServiceLocator from the Microsoft Patterns and Practices team (http://www.codeplex.com/CommonServiceLocator) This allows us to use Castle Windsor without making our code dependent on it, such that we could later switch it out for StructureMap, NInject, or any other IoC container that has a ServiceLocator Adapter (see the list of those here as well)
First, setting up CastleWindsor and the common service locator. This code will be called from Application_Start in your Global.asax page:
IWindsorContainer container = new WindsorContainer();
container.AddComponent("authenticationProvider",
typeof(IAuthenticationProvider), typeof(FormsAuthenticationProvider));
container.AddComponent("userRepository",
typeof(IUserRepository), typeof(UserRepository));
container.AddComponent("membershipProvider",
typeof(IMembershipProvider), typeof(MembershipProvider));
ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(container));Easy enough, yes? Now you can see how the default constructors we set up for our controllers work
public class MembershipController: Controller { private readonly IAuthenticationProvider authenticationProvider; private readonly IMembershipProvider membershipProvider; public MembershipController(IAuthenticationProvider authenticationProvider, IMembershipProvider membershipProvider) { this.authenticationProvider = authenticationProvider; this.membershipProvider = membershipProvider; } public MembershipController():this(ServiceLocator.Current.GetInstance<IAuthenticationProvider>(), ServiceLocator.Current.GetInstance<IMembershipProvider>()) {} <...>
When the controller is instantiated by a test method, we can pass in a mocked IAuthenticationProvider and IMembershipProvider When it is instantiated using the default, parameterless constructor, it gets its implementations of IAuthenticationProvider and IMembershipProvider from the concrete implementations registered with our IoC contaner (Windsor) through the CommonServiceLocator. Viola!
Oh, but we’re not done. Here’s something about Asp.Net Mvc that I think is just exceptionally cool. Just by adding this one line of code:
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container));
…we can now remove all those default parameterless constructors from our Controllers, and all the calls to the ComonServiceLocator, and let the ControllerFactory do it for us. We can still pass in mock objects when testing and the ControllerFactory will use the WindsorControllerFactory from the MvcContrib project to locate the implementations of the objects required by the controller’s constructor. Groovy, huh?
So, all together, here’s the code from Application_Start
protected void Application_Start() { IWindsorContainer container = new WindsorContainer(); ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(container)); container.AddComponent("authenticationProvider", typeof(IAuthenticationProvider), typeof(FormsAuthenticationProvider)); container.AddComponent("userRepository", typeof(IUserRepository), typeof(UserRepository)); container.AddComponent("membershipProvider", typeof(IMembershipProvider), typeof(MembershipProvider)); ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(container)); <...> }
So, there you have it. And switching out CastleWindsor for another IoC container (that has adapters for ServiceLocator and ControllerFactory) is easy.
25th
FEB
Alt.Net Lunch and Learn: Asp.Net MVC
Posted by indomitablehef | Filed under Asp.Net MVC, Alt.Net
I’m presenting at the Nashville Alt.Net user group Lunch and Learn tomorrow at 11:30. New venue this time, but still in Maryland Farms. Check the details here: http://groups.google.com/group/nashvillealtnet-discuss
Oh, yeah…the topic: Introduction to Asp.Net MVC. As usual, the presentation will be short and hopefully the discussion will be long.
9th
FEB
Forms Authentication in Asp.Net MVC, Part III
Posted by indomitablehef | Filed under Asp.Net MVC
This is part 3 of 4
Forms Authentication in Asp.Net MVC
Moving on from where we left off in part II, we now need to implement our MembershipProvider.
We have two final tasks left to accomplish
- Retrieve the User from the datastore
- Check to see if the username and password are valid
Following the Single Responsibility Principle, we’ll separate these, using the MembershipProvider for validating the username/password, and a UserRepository for retrieving the user from the datastore.
From last time, recall that our IMembershipProvider looks like this:
1 2 3 4 | public interface IMembershipProvider { bool ValidateUser(string userName, string password, out string validationMessage); } |
Now we’re going to need a user repository, or some other form of User data access object. I’m using NHibernate, but you could use Linq to Sql or your ORM of choice. Either way, the interface for our IUserRepository is quite simple. I leave the implementation entirely up to you.
1 2 3 4 | public interface IUserRepository { User GetByUserName(string userName); } |
So, we can implement our MembershipProvider like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | public class MembershipProvider : IMembershipProvider { private IUserRepository userRepository; public MembershipProvider(IUserRepository userRepository) { this.userRepository = userRepository; } public MembershipProvider() : this(ServiceLocator.Current.GetInstance<IUserRepository>()) { } public bool ValidateUser(string userName, string password, out string validationMessage) { User user; try { user = userRepository.GetByUserName(userName); if (user == null) { validationMessage = "invalid username"; return false; } if (user.Password != password) { validationMessage = "invalid password"; return false; } validationMessage = ""; return true; } catch (Exception ex) { throw new Exception("Encountered an error while attempting to validate username and password",ex); } } } |
And we can test it like this
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | [TestFixture] public class MembershipProviderTests { #region Setup/Teardown [SetUp] public void SetUp() { mockedUserRepository = MockRepository.GenerateMock<IUserRepository>(); provider = new MembershipProvider(mockedUserRepository); } #endregion private IMembershipProvider provider; private IUserRepository mockedUserRepository; [Test] public void IsValidWhenUserNameAndPasswordMatchExistingUser() { //arrange var user = MockRepository.GenerateStub<User>(); user.UserName = "billy.pilgrim"; user.Password = "tralfamador"; mockedUserRepository.Expect(x => x.GetByUserName("billy.pilgrim")).Return(user); string validationMessage = ""; //act var isValid = provider.ValidateUser("billy.pilgrim", "tralfamador", out validationMessage); //assert Assert.IsTrue(isValid); } [Test] public void IsInValidWhenUserDoesNotExist() { //arrange mockedUserRepository.Expect(x => x.GetByUserName("billy.pilgrim")).Return(null); string validationMessage = ""; //act var isValid = provider.ValidateUser("billy.pilgrim", "tralfamador", out validationMessage); //assert Assert.IsFalse(isValid); Assert.AreEqual("invalid username",validationMessage); } [Test] public void IsInValidWhenPasswordDoesNotMatch() { //arrange var user = MockRepository.GenerateStub<User>(); user.UserName = "billy.pilgrim"; user.Password = "tralfamador"; mockedUserRepository.Expect(x => x.GetByUserName("billy.pilgrim")).Return(user); string validationMessage = ""; //act var isValid = provider.ValidateUser("billy.pilgrim", "wrongpassword", out validationMessage); //assert Assert.IsFalse(isValid); Assert.AreEqual("invalid password",validationMessage); } } |
And we’re basically done. There’s one more installment coming, though. We’ll take a look at setting up the IoC container used in these examples (Castle Windsor) and do a little refactoring.
6th
FEB
Forms Authentication in Asp.Net MVC, Part II
Posted by indomitablehef | Filed under Asp.Net MVC
This is part 2 of 4
Forms Authentication in Asp.Net MVC
Continuing on from where we left off in part I, we now need to implement the code that actually does the Authentication against whatever user store we have in place. The default MVC project uses the Membership provider for Asp.Net, and that works just fine. I need more control than that, though, so let’s take a look at the next steps.
Last time, I mentioned the MembershipController and the Login action. Once the Login view has been rendered, it submits to the Authenticate action, also on the MembershipController.
The Login View:
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage" %> <%@ Import Namespace="MyProject.Web.Controllers" %> <asp:Content ID="content" ContentPlaceHolderID="MainContentPlaceHolder" runat="server"> <h1> Login</h1> <% if( ViewData["ErrorMessage"] != null ){ %> <p> <% =ViewData["ErrorMessage"] %></p> <% } %> <% using( Html.BeginForm("Authenticate", "Membership" )){ %> <fieldset> <legend>Login</legend> <div> <label for="userName"> User Name:</label> <% =Html.TextBox( "userName" ) %></div> <div> <label for="password"> Password:</label> <% =Html.Password( "password" ) %></div> <div> <label for="rememberMe"> Remember Me:</label> <input type="checkbox" id="rememberMe" name="rememberMe" checked="checked" value="checked" /></div> <div> <% =Html.SubmitButton() %></div> <% =Html.Hidden( "returnUrl", "/" ) %> </fieldset> <% } %> </asp:Content>
And the login action on the MembershipController
1 2 3 4 5 6 7 8 | public class MembershipController: Controller { public ActionResult Login() { return View("Login"); } } |
Now we need an Authenticate action, for when the Login form is submitted
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public ActionResult Authenticate(string userName, string password, string rememberMe, string returnUrl) { string validationMessage = ""; if (membershipProvider.ValidateUser(userName, password, out validationMessage)) { authenticationProvider.SetAuthCookie(userName, (rememberMe != null)); return new RedirectResult(returnUrl); } else { ViewData["ErrorMessage"] = validationMessage; return View("Login"); } } |
Notice some things here. We’re using the authenticationProvider we started with in part I, and a new membershipProvider. We’ve also added another method to our AuthenticationProvider, SetAuthCookie. This simply wraps the FormsAuthentication.SetAuthCookie method.
So, now our IAuthenticationProvider looks like this:
1 2 3 4 5 6 | public interface IAuthenticationProvider { bool IsAuthenticated(ControllerContext context); void RedirectToLogin(ControllerContext context); void SetAuthCookie(string userName, bool createPersistentCookie); } |
Our FormsAuthenticationProvider implementation looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public class FormsAuthenticationProvider: IAuthenticationProvider { public virtual bool IsAuthenticated(ControllerContext context) { return context.HttpContext.User.Identity.IsAuthenticated; } public virtual void RedirectToLogin(ControllerContext context) { context.HttpContext.Response.Redirect(FormsAuthentication.LoginUrl + string.Format("?ReturnUrl={0}", context.HttpContext.Request.Url.AbsolutePath), true); } public virtual void SetAuthCookie(string userName, bool createPersistentCookie) { FormsAuthentication.SetAuthCookie(userName, createPersistentCookie); } } |
And we need to provide the Authentication and Membership provider to our MembershipController, so we add them in the constructors. The whole thing, with the constructors, Login Action and Authenticate action looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | public class MembershipController: Controller { private readonly IAuthenticationProvider authenticationProvider; private readonly IMembershipProvider membershipProvider; public MembershipController(IAuthenticationProvider authenticationProvider, IMembershipProvider membershipProvider) { this.authenticationProvider = authenticationProvider; this.membershipProvider = membershipProvider; } public MembershipController():this(ServiceLocator.Current.GetInstance<IAuthenticationProvider>(), ServiceLocator.Current.GetInstance<IMembershipProvider>()) {} public ActionResult Login() { return View("Login"); } public ActionResult Authenticate(string userName, string password, string rememberMe, string returnUrl) { string validationMessage = ""; if (membershipProvider.ValidateUser(userName, password, out validationMessage)) { authenticationProvider.SetAuthCookie(userName, (rememberMe != null)); return new RedirectResult(returnUrl); } else { ViewData["ErrorMessage"] = validationMessage; return View("Login"); } } } |
Now we can write some good tests for our MembershipController, mocking the MembershipProvider and the AuthenticationProvider
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | [TestFixture] public class MembershipControllerTests { private MembershipController controller; private IMembershipProvider mockedMembershipProvider; private IAuthenticationProvider mockedAuthenticationProvider; [SetUp] public void SetUp() { mockedMembershipProvider = MockRepository.GenerateMock<IMembershipProvider>(); mockedAuthenticationProvider = MockRepository.GenerateMock<IAuthenticationProvider>(); controller = new MembershipController(mockedAuthenticationProvider, mockedMembershipProvider); } [Test] public void CanInitUserLogin() { ViewResult result = controller.Login().AssertViewRendered(); } [Test] public void CanAuthenticate() { //arrange string validationMessage = ""; mockedMembershipProvider.Expect(x => x.ValidateUser("", "", out validationMessage)).IgnoreArguments().Return(true); mockedAuthenticationProvider.Expect(x => x.SetAuthCookie("", false)).IgnoreArguments(); //act, assert RedirectResult redirectResult = controller.Authenticate("username", "password", "rememberme", "/").AssertHttpRedirect(); mockedMembershipProvider.VerifyAllExpectations(); mockedAuthenticationProvider.VerifyAllExpectations(); } [Test] public void CanRedirectToLoginWhenNotAuthenticated() { //arrange var controller = new MembershipController(mockedAuthenticationProvider, mockedMembershipProvider); string validationMessage = ""; //when validate user returns false mockedMembershipProvider.Expect(x => x.ValidateUser("", "", out validationMessage)).IgnoreArguments().Return(false); //act, assert ViewResult viewResult = controller.Authenticate("username", "password", "rememberme", "/").AssertViewRendered(); Assert.IsNotNull(controller.ViewData["ErrorMessage"]); mockedAuthenticationProvider.AssertWasNotCalled(x => x.SetAuthCookie("username", true)); mockedMembershipProvider.VerifyAllExpectations(); } } |
Notice the AssertViewRendered and AssertHttpRedirect extension methods. These are part of the MvcContrib TestHelper library.
Finally, we’ll take a quick look at our IMembershipProvider interface
1 2 3 4 | public interface IMembershipProvider { bool ValidateUser(string userName, string password, out string validationMessage); } |
…but I’ll need to leave the implementation of that for part III, coming soon, which can be found here.
6th
Forms Authentication in Asp.Net MVC
Posted by indomitablehef | Filed under Asp.Net MVC, TDD
This is part 1 of 4
Forms Authentication in Asp.Net MVC
I’ve been working on a testable solution for my Asp.Net MVC project. I have a solution that I think works, but I’d love to hear comments/criticisms if you’ve got any.
First, set up forms authentication in web.config:
<authentication mode="Forms"> <forms loginUrl="Membership/Login" defaultUrl="/" /> </authentication>
Now you’ll need an interface for IAuthenticationProvider
1 2 3 4 5 | public interface IAuthenticationProvider { bool IsAuthenticated(ControllerContext context); void RedirectToLogin(ControllerContext context); } |
And an implementation, FormsAuthenticationProvider
1 2 3 4 5 6 7 8 9 10 11 12 | public class FormsAuthenticationProvider: IAuthenticationProvider { public virtual bool IsAuthenticated(ControllerContext context) { return context.HttpContext.User.Identity.IsAuthenticated; } public virtual void RedirectToLogin(ControllerContext context) { context.HttpContext.Response.Redirect(FormsAuthentication.LoginUrl + string.Format("?ReturnUrl={0}", context.HttpContext.Request.Url.AbsolutePath), true); } } |
I’m doing authentication on Controllers using an ActionFilterAttribute
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public class RequiresAuthenticationAttribute : ActionFilterAttribute { private IAuthenticationProvider authenticationProvider; public RequiresAuthenticationAttribute(IAuthenticationProvider provider) { authenticationProvider = provider; } public RequiresAuthenticationAttribute() : this(ServiceLocator.Current.GetInstance<IAuthenticationProvider>()) {} public override void OnActionExecuting(ActionExecutingContext filterContext) { if (!authenticationProvider.IsAuthenticated(filterContext)) { authenticationProvider.RedirectToLogin(filterContext); } } } |
A couple of things to notice about this:
I have a test-specific constructor, that allows me to pass in the IAuthentication provider. I’m using Castle Windsor as an IoC container, and the LocatorProvider for ServiceLocator. In my parameter-less constructor, I simply get the configured IAuthenticationProvider from the IoC container.
To use my RequiresAuthentication attribute, I just decorate the controller with it, like this
1 2 3 4 5 6 7 8 | [HandleError] [RequiresAuthentication] public class HomeController : Controller { public ActionResult Index() { return View(); } } |
Now for my tests
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | [TestFixture] public class RequiresAuthenticationAttributeTests { [Test] public void CanRedirectToLoginWhenNotAuthenticated() { //arrange var mockedProvider = MockRepository.GenerateMock<IAuthenticationProvider>(); mockedProvider.Expect(x => x.IsAuthenticated(null)).IgnoreArguments().Return(false); mockedProvider.Expect(x => x.RedirectToLogin(null)).IgnoreArguments(); //act var attribute = new RequiresAuthenticationAttribute(mockedProvider); attribute.OnActionExecuting(null); //assert mockedProvider.VerifyAllExpectations(); } [Test] public void CanPassThroughWhenAuthenticated() { //arrange var mockedProvider = MockRepository.GenerateMock<IAuthenticationProvider>(); mockedProvider.Expect(x => x.IsAuthenticated(null)).IgnoreArguments().Return(true); //act var attribute = new RequiresAuthenticationAttribute(mockedProvider); attribute.OnActionExecuting(null); //assert mockedProvider.AssertWasNotCalled(x => x.RedirectToLogin(null)); mockedProvider.VerifyAllExpectations(); } } |
Using Rhino Mocks, I just mock the IAuthenticationProvider and pass it in to the constructor of my RequiresAuthenticationAttribute.
The code inside the FormsAuthenticationProvider relies on httpContext, which is damn near impossible to mock…I tried. So with this solution, I’ve at least isolated that code so that I can test everything else. I would LOVE to hear your thoughts on this…be brutal.
Update: The authentication section of Web.config indicates that the loginurl is Membership/Login….that means you’ll need a MembershipController with a Login action to display the login view, like this
1 2 3 4 5 6 7 | public class MembershipController: Controller { public ActionResult Login() { return View("Login"); } } |
Update: continue on to Part II, where we dig into the MembershipController
Recent Posts
Recent Comments
- Open Floor Plan vs. Private Offices « Step Into Design on It's Caves AND Commons...
- indomitablehef on Forms Authentication in Asp.Net MVC, Part II
- Dugald Wilson on Forms Authentication in Asp.Net MVC, Part II
- MyWeeklyLinks – Week 5 « Ole Morten Amundsen on Implementing Done, In Process, and Ready Queues in LeanKit Kanban
- indomitablehef on Schema Generation using FluentNHibernate and S#arp Architecture
Categories
- .Net (5)
- Agile (17)
- Alt.Net (3)
- Anti Patterns (3)
- Asp.Net MVC (9)
- Continuous Integration (4)
- Craftsmanship (1)
- CruiseControl.Net (1)
- DDD (6)
- DevLink (2)
- jQuery (2)
- Kanban (4)
- Lean (2)
- LeanKit (3)
- NAnt (2)
- NHibernate (2)
- ORM (1)
- Personal (4)
- Productivity (6)
- qUnit (2)
- Refactoring (1)
- S#arp Architecture (2)
- SOLID (1)
- SqlTdd (5)
- TDD (17)
- Tools (12)
- Uncategorized (11)
- Visual Studio (4)


