Jon Kruger -
  • About Me
  • Blog
  • Values
  • Presentations
About Me
Blog
Values
Presentations
  • About Me
  • Blog
  • Values
  • Presentations
Jon Kruger
ASP.NET MVC

Why ASP.NET MVC is better than WebForms: Repeatability

A lot of people out there are asking, “Why is ASP.NET MVC better than WebForms?” or “Why should I switch from WebForms to MVC?” Usually the response includes these items:

  • Clear separation of concerns
  • Testability – support for Test-Driven Development
  • Fine-grained control over HTML and JavaScript

This doesn’t always mean much if people don’t do TDD and are fine without fine-grained control over HTML and JavaScript.

I’d like to add one more thing to the list: repeatability. Most of us are writing line-of-business applications, and when you write these kinds of web sites, there are common UI patterns that emerge:

  • A grid that contains a list of data, and might have Add/Edit/Delete buttons above it.
  • A screen that contains a bunch of input fields and Save and Cancel buttons.
  • If you save a screen with input fields and a validation error occurs, go back to the same screen and show the validation errors at the top of the screen.

Here’s where the repeatability comes in. Let’s take the Add/Edit/Delete grid screen as an example. I should be able to write code to handle this pattern once and never have to do it again. The next time I do this screen, I should only have to write code to do the following:

  • Tell the grid what data to display
  • Tell the grid which buttons to show (if any)

The code looks like this:


    <%= Html.JQueryGrid()
        .LoadDataFromUrl("/customers/GetCustomerData")
        .AddEditDeleteButtons()
        .Caption("Customers")
        .ExpandToFitAllRows()
        .Columns(columns =>
        {
            columns.For(x => x.Id).Visible(false);
            columns.For(x => x.CompanyName).AsEditLink();
            columns.For(x => x.Address);
            columns.For(x => x.City);
            columns.For(x => x.State).Width(50);
            columns.For(x => x.Zip).Width(50);
            columns.For(x => x.CompanyEmail);
            columns.For(x => x.PhoneNumber).Width(100);
            columns.For(x => x.FaxNumber).Width(100);
            columns.For(x => x.Salesperson).Width(100);
        }) %>

Pretty clear what that does, right?

Notice what I’m not writing:

  • Code that tells the site what to do when Add, Edit, or Delete are clicked
  • Code that enables/disables the buttons based on what is selected in the grid
  • Grid paging code (other than stored proc or LINQ code that handles this, if necessary)
  • Any JavaScript code (it’s all spit out by the code that renders the grid HTML)

I could write the code to do these things, but I’m not going to unless I have to because I need to do something different than the norm. I’m going to let my conventions and HTML helpers do the work.

So why is MVC better at this than WebForms? Because of separation of concerns. In this case, separation of concerns does not mean having a presentation layer, business layer, and data access layer. I’m talking about separation of concerns within the UI layer (your business layer and data access layer will be the same regardless of whether you use MVC or WebForms).

Let’s say that I have a screen with a grid with a list of data. The grid has a pager and Add/Edit/Delete buttons. Here are all of the pieces and parts that go into implementing this in MVC:

  • HTML code for the page – View
  • Code that writes out HTML and JavaScript for grid – HTML helper fluent interface + HTML renderer + jQuery grid
  • Get data for the view – controller method
  • Store data for the view – view model, populated with very little or no code using AutoMapper
  • Handle AJAX requests from the grid pager – model binder, which passes data to controller
  • Return data in a format the grid pager can understand – method on base controller class (lets MVC convert data to JSON and call Response.Write())
  • Verify security permissions – action filter attributes on controller methods
  • Handle Add/Edit/Delete button clicks – JavaScript written out by HTML grid render
  • Determine which screen to show when button is clicked – action filter attribute
  • Get data for Add/Edit/Delete screens – controller method

How would you do this in WebForms?

  • HTML code for the page – View
  • Code that writes out HTML and JavaScript for grid – 3rd party grid control
  • Get data for the view – code behind (calling into business layer)
  • Store data from the view – copied into controls in code behind
  • Handle AJAX requests from the grid pager – web service, configured to accept AJAX requests
  • Return data in a format the grid pager can understand – some method + JSON formatter + Response.Write()
  • Verify security permissions – code behind
  • Handle Add/Edit/Delete button clicks – custom JavaScript
  • Determine which screen to show when button is clicked – code behind
  • Get data for Add/Edit/Delete screens – code behind (calling into business layer)

Notice the pattern? In WebForms the code behind is doing a lot (not to mention the fact that you can’t easily unit test code behind files). Big code behind files do not lend themselves to repeatability — but small classes that have specific responsibilities are very reusable. This is why separation of concerns matter. In my MVC screen, I deal with a view, controller, view model, model binders, HTML helpers, grid renders, and action filter attributes. In WebForms, I have a view and a code behind.

Having these small classes leads to reusability. I can use the HTML helper that renders the grid for my page on another page that renders a grid. I can create a controller attribute that will check to see if a user is logged in, or in a certain role. I now never have to write code to check that again – I just put an attribute on a controller method and I’m done with security.

It’s also amazingly easy to write code when you’re working with small, specific classes. Can you tell me what this attribute does?

[RequiresPermission(Permissions.AddUser)]

How about this one?

[RedirectWhenGridToolbarButtonClicked]

All of this leads to reusability, less bugs, code that is easy to read and write, and less development time. The ultimate goal is less development time and better quality. By reusing code, you get things done faster (because you write less code) and you have fewer bugs (because you write less code).

On my current project, development time is way down. The screen that I’ve been talking about with the grid and Add/Edit/Delete buttons and paging, and all that? Done in 2 hours. Basic input screen with validation – 4 hours. The first screen with a grid took a few days, but I wrote all the HTML helpers and renderers that write out the HTML and JavaScript for the grid, wrote the model binder that takes HttpRequest form inputs and calls controller methods (based on conventions), and wrote all the code to receive AJAX requests and send back a response. On the next screen, I call my HTML helper methods that write out the grid HTML and pass it some configuration parameters, create some controller methods that load and save data, and I’m done.

This post didn’t cover MVC basics, like what controllers, view models, and model binders are. There are plenty of posts that explain that. I’m just hoping to explain that the reusability of ASP.NET MVC can drastically reduce development time and make things a lot easier for you.

May 26, 2009by Jon Kruger
.NET, ASP.NET MVC, unit testing

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.

April 13, 2009by Jon Kruger
ASP.NET MVC

ASP.NET MVC: Pass parameters when redirecting from one action to another

In ASP.NET MVC, it’s common to have a situation where you post to one controller action and then redirect to another controller action. Let’s say that you want to pass values from the first controller method to the other. The problem is that in out-of-the-box ASP.NET MVC, there is no way to redirect to another action and pass a parameter into the action that you are redirecting to. Here is one way you can get around this problem:

public class AccountController : Controller
{
    [AcceptGet]
    public ActionResult Index(IndexViewModel model)
    {
        model.Message = (string) TempData["Message"];

        return View(model);
    }

    [AcceptPost]
    public ActionResult Save(SaveUpdateModel model)
    {
        // save the information
        TempData["Message"] = model.Message;
        return RedirectToAction("Index");
    }
}

The reason that you would do a redirect in this case is so that (a) you can reuse the code in the Index method and (b) you are redirecting to a GET operation, so if the user clicks Refresh in their browser, it won’t try to re-post the previous page.

I don’t really like how that code works, for various reasons:

  • I’m using hardcoded strings (“Index” and “Message”). These might not get caught by refactoring tools if I want to change names, and I don’t get compile time checking on them.
  • In the Index() method, I have to grab the value out of TempData. That works fine if you’re being redirected from the Save() action, but what if I’m being redirected from another action? What if I’m not being redirected from anywhere and the user is accessing the action directly? Ideally, when the Index() method is called, it should have everything that it needs in its parameters at the beginning of the method.

Personally, I don’t like to see TempData or ViewData anywhere in my controller methods. Don’t get me wrong, I need them and I’m going to use them, but I want it all done under the covers. I favor the “One Model In, One Model Out” pattern, where each controller action method takes in one model parameter (or none) and returns another model. Doing it this way allows me to avoid the use of magic strings and hashtables. I want my code to look like this:

[PassParametersDuringRedirect]
public class AccountController : Controller
{
    [AcceptGet]
    public ActionResult Index(IndexPresentationModel model)
    {
        return View(model);
    }

    [AcceptPost]
    public ActionResult Save(SaveUpdateModel model)
    {
        // save the information

        var presentationModel = new IndexPresentationModel();

        presentationModel.Message = model.Message;

        return this.RedirectToAction(c => c.Index(presentationModel));
    }
}

This code does exactly what I want. Now…

  • I don’t have any magic strings.
  • Everything is strongly typed.
  • The parameter passed to the Index() method will always be complete. I don’t have to load anything out of TempData to get it to work.

One thing I love about ASP.NET MVC is that it is very extensible, so you can usually make it do what you want. This is the purpose of the MVCContrib project — people extending ASP.NET MVC to make it even better.

You may notice that in the code snippet above, I decorated my controller class with the [PassParametersDuringRedirect] attribute. Now, any parameters that I pass into RedirectToAction() will get passed into the action that I redirected to.

One slight problem… this new version of RedirectToAction() is an extension method on the Controller class, which means to call it, you would have to write “this.RedirectToAction()”. If you don’t want to have to write “this.” every time, you can just create a base controller class that has this method:

protected RedirectToRouteResult RedirectToAction(Expression> action) 
    where T : Controller
{
    return ControllerExtensions.RedirectToAction(this, action);
}
April 6, 2009by Jon Kruger

About Me

I am a technical leader and software developer in Columbus, OH. Find out more here...

I am a technical leader and software developer in Columbus, OH, currently working as a Senior Engineering Manager at Upstart. Find out more here...