Asp.Net MVC programming advice. Toodles, Evan Nagle.
Jul
01

Tree Cartoon The Big Boy MVC Series    Part 22: Mistakes Make Me Human. Fixing Mistakes Makes Me Brad Wilson

Why me? I was just sitting here. Minding my own business. Then, bam.

I was trying to figure out the quickest, simplest way to introduce flexible Editor Templates into my project. And, when it comes to building your Editor (and Display) Templates, Brad Wilson is your happy pappy.

Anyways, like I was saying, I was perusing Brad Wilson’s great mini blog series about MVC Templates, and, out of nowhere, bam. I started to get all teary eyed. Because reading Brad Wilson’s blog is like watching a really good lifeguard save a drowning person from, well, drowning. And I, my friends, was about to become that drowning person.

Okay. Maybe I didn’t cry. And maybe I’m overstating the drama here. But I did exclaim a “Damn It!” or two, and I do have Brad Wilson to thank for it. Here’s why. In the comments section of the post entitled Part 4: Custom Object Templates, Brad writes:

Personally, my recommendation for people who want strict SoC (like I do) is to use ViewModels and only place the annotations on the view model. There are other issues with directly model binding to things like LINQ to SQL or LINQ to Entities (for example, if you’re not careful, you can destroy your associations or inadvertently let a bad guy bind data into something that wasn’t originally shown in the editor), so I generally always recommend view models anyway.

Why so verbose, Brad? This photo more directly expresses the SoC sentiment that you’re trying to divulge:

Capture1 The Big Boy MVC Series    Part 22: Mistakes Make Me Human. Fixing Mistakes Makes Me Brad Wilson

Lucky puppies.

Hopefully, by now, you have a decent idea of what I did wrong. Proverbially speaking, I annotated the wrong dog. And now that I’m ready to build some custom MVC templates, I either need to (a.) fix my mistake before continuing (i.e. create and annotate the ViewModel dog), or (b.) pretend that I didn’t make a mistake, whistle a little, and keep chugging along.

I think there are two lessons to learn in all of this. The first: nap. Sleeping/napping helps to reinvigorate the brain. And a reinvigorated brain is much more likely to coherently yelp, “Hmm. Maybe I’m doing this stupidly.” The second: when working with a framework, be a baby bear. If you’re “meshing well” with your framework (MVC, that is) then the work that you’re doing shouldn’t be too extremely hard, and it shouldn’t be too extremely easy. To Goldilocks’ blonde-haired delight, it should be “just right.” And you know it’s not “just right” when you start desperately Googling (or Binging [the Microsoft kind, not the alcoholic kind]) crazy and weird and desperate “How To’s”.

Okay, enough drama. Tears, destroyed. Let’s go ahead and add an extra layer of awesomeness to our project. We’ll call it Brad. After the band. No, actually, we’ll call it the ViewModel layer. If this is the first time that you’ve ever built a ViewModel layer before, that’s okay. You might want to check out Steve Michelotti’s post, MVC ViewModel Patterns. And, perhaps even more salient for our purposes, you might also want to check out Bengt Berge’s post on Using AutoMapper to Map ViewModels. We’ll be using AutoMapper a little bit later.

Step 1: Admit your mistakes. Call everyone that you love and apologize for your misdeeds. Start with your Grandmother. Don’t hesitate. You can actually delete all of the Buddy class crap that we created in this post. I feel better already. Like a cancerous weight has been lifted from my developmental testicles.

Step 2: Run your unit tests. Make sure that you didn’t inadvertently break anything. If you’ve been following my instructions to a T, all of your tests should still pass (minus the Validation tests, which you should have deleted in step 1). If your tests don’t pass, refactor your code until they do or until a good television show starts up.

Step 3: Create a ViewModels folder. Inside your ViewModels folder, create an AutoMapper folder. Easy enough. As always, we’ll want to create the same folders in our Test project. Until, voila:

folders e1277958937450 The Big Boy MVC Series    Part 22: Mistakes Make Me Human. Fixing Mistakes Makes Me Brad Wilson

Step 4: In your ViewModels folder, create a FoodAdd class. This is our first ViewModel class. All of our ViewModel classes will be named {Controller}{Action}.cs. Again, for form validation, we’ll add DataAnnotations. Notice that the properties in this ViewModel are perfectly aligned with the form fields in our page prototype. In my earlier post, I didn’t have such a nice juxtaposition.


using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

using Big.Fat.Dish.Models;

namespace Big.Fat.Dish.ViewModels
{
    public class FoodAdd
    {
        [Required, StringLength(200), DisplayName("Food Name")]
        public string FoodName { get; set; }

        [Required, StringLength(200), DisplayName("Restaurant Name")]
        public string RestaurantName { get; set; }

        [Required, StringLength(600), DisplayName("Restaurant Address")]
        public string OneLineAddress { get; set; }
    }
}

Step 5: Download AutoMapper. You can download AutoMapper here. The documentation is still a little sparse, so, if you want to learn about AutoMapper, check out Bengt’s post. You can also peruse Matt Hinze’s post, which explains how you might implement AutoMapper in Scott Hanselman’s NerdDinner project. If you still want more, there are 168 AutoMapper questions on StackOverflow, many of which will help you get acquainted.

Step 6: Create some AutoMapper unit tests. We’ll be passing a ViewModel class to our HttpPost action. In our post action, we’ll want to convert or ViewModel class (if it’s valid) into a Model class. If you like the Hasselhoff allegory, we’re metaphorically trading in the bottom puppy for the puppy that’s closer to Hass’s impeccable pectorals. It’s a deal!

For testing, we’ll create two test classes. The first will test our AutoMapper Profile (we’ll create this Profile in a minute). Lucky for us, AutoMapper exposes a nice method for validating our configuration in one painless, jaw-dropping swoop:


using Microsoft.VisualStudio.TestTools.UnitTesting;
using AutoMapper;

namespace Big.Fat.Dish.Tests.ViewModel.AutoMaps
{

    [TestClass]
    public class ViewToDomainProfileTest
    {
        [TestInitialize]
        public void TestInit()
        {
            ViewToDomainProfile.Initialize();
        }

        [TestMethod]
        public void ViewModels_AutoMaps_Configured()
        {
            Mapper.AssertConfigurationIsValid(ViewToDomainProfile.NameOfProfile);
        }
    }
}

In our second test, we’ll be verifying that our Mapper correctly converts a FoodAdd class into a Food class.


using Microsoft.VisualStudio.TestTools.UnitTesting;
using AutoMapper;
using Big.Fat.Dish.Models;
using Big.Fat.Dish.ViewModels;
using Big.Fat.Dish.ViewModels.AutoMaps;

namespace Big.Fat.Dish.Tests.ViewModel.AutoMaps
{
    [TestClass]
    public class FoodAddConverterTest
    {
        FoodAdd form = new FoodAdd
        {
            FoodName = "Hotdog",
            RestaurantName = "Dick's",
        };

        [TestInitialize]
        public void TestInit()
        {
            ViewToDomainProfile.Initialize();
        }

        [TestMethod]
        public void ViewModels_AutoMaps_FoodAdd_Food_Map()
        {
            Mapper.CreateMap<FoodAdd, Food>();
            Mapper.AssertConfigurationIsValid();
        }

        [TestMethod]
        public void ViewModels_AutoMaps_FoodAdd_Food_Name_Mapped()
        {
            Food food = form.Map();
            Assert.IsNotNull(food);
            Assert.AreEqual(form.FoodName, food.Name);
        }

        [TestMethod]
        public void ViewModels_AutoMaps_FoodAdd_Restaurant_Name_Mapped()
        {
            Food food = form.Map();
            Assert.IsNotNull(food.Restaurant);
            Assert.AreEqual(form.RestaurantName, food.Restaurant.Name);
        }
    }
}

Step 7: Create a ViewToDomainProfile class. In our Profile class, we’ll specify all of the object-to-object mappings that we want to handle with AutoMapper. We’ll place this class in our AutoMaps folder.


using System;
using System.Collections.Generic;
using AutoMapper;
using Big.Fat.Dish.Models;

namespace Big.Fat.Dish.ViewModels.AutoMaps
{
    public class ViewToDomainProfile : Profile
    {
        public const string NameOfProfile = "ViewToDomainProfile";
        public override string ProfileName
        {
            get
            {
                return NameOfProfile;
            }
        }

        protected override void Configure()
        {
            CreateMap<FoodAdd, Food>().ConvertUsing<FoodAddMap>();
        }

        public static void Initialize()
        {
            Mapper.Initialize(x => x.AddProfile<ViewToDomainProfile>());
        }
    }
}

Step 8: Create a FoodAddMap class. This class will be responsible for converting a FoodAdd class into a Food class. Notice how stupidly simple the conversion is (for now). This class should also be plopped into your AutoMaps folder:


using Big.Fat.Dish.Models;
using AutoMapper;

namespace Big.Fat.Dish.ViewModels.AutoMaps
{
    public class FoodAddMap : TypeConverter<FoodAdd, Food>
    {
        protected override Food ConvertCore(FoodAdd source)
        {
            return new Food
            {
                Name = source.FoodName,
                Restaurant = new Restaurant
                {
                    Name = source.RestaurantName,
                }
            };
        }
    }
}

Step 9: Create a MappedTo class. All of our ViewModel classes will inherit from our MappedTo class. Place this class in the AutoMaps folder:


using AutoMapper;

namespace Big.Fat.Dish.ViewModels//.AutoMaps
{
    public class MappedTo<T>
    {
        public T Map()
        {
            return (T)Mapper.Map(this, this.GetType(), typeof(T));
        }
    }
}

Step 10: Set your FoodAdd ViewModel to inherit from MappedTo<Food>. Once you’ve done that, a call to Map() on a FoodAdd class will return a Food class. That’s what we wanted all along.


using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using Big.Fat.Dish.Models;

namespace Big.Fat.Dish.ViewModels
{
    public class FoodAdd : MappedTo<Food>
    {
        [Required, StringLength(200), DisplayName("Food Name")]
        public string FoodName { get; set; }

        [Required, StringLength(200), DisplayName("Restaurant Name")]
        public string RestaurantName { get; set; }

        [Required, StringLength(600), DisplayName("Restaurant Address")]
        public string OneLineAddress { get; set; }
    }
}

Step 11: In your global.asax file, initialize AutoMapper. This is how AutoMapper gets all its kicks:


protected void Application_Start()
{
	AreaRegistration.RegisterAllAreas();
	ViewToDomainProfile.Initialize();

	RegisterRoutes(RouteTable.Routes);
}

Step 12: Run all of your unit tests. Pray that they pass. They should pass. If they don’t, blame yourself. Because, well, I’m in good shape:

tests e1277974490122 The Big Boy MVC Series    Part 22: Mistakes Make Me Human. Fixing Mistakes Makes Me Brad Wilson


Okay. Let’s recap. So, we started with a system that worked something like this (doodle time!):

Old The Big Boy MVC Series    Part 22: Mistakes Make Me Human. Fixing Mistakes Makes Me Brad Wilson

And we introduced a new ViewModel layer, which will allow for easier templating, easier validation, and a more stringent separation of concerns. Can’t complain about that!

new The Big Boy MVC Series    Part 22: Mistakes Make Me Human. Fixing Mistakes Makes Me Brad Wilson

Move on to Part 23: Baby Got Postbacks, a Preamble.

Read More

You can leave a response, or trackback from your own site.

5 Responses to “The Big Boy MVC Series — Part 22: Mistakes Make Me Human. Fixing Mistakes Makes Me Brad Wilson”

 
  1. [...] Move on to Part 22: Mistakes Make Me Human. Fixing Mistakes Makes Me Brad Wilson. [...]

  2. codinghobbit says:

    Hi…emm WeirdLove..

    This has been one the most entertaining intro’s in to MVC i have yet to read. On a serious note – this is a MVC A to Z series worth a read!!

    Great stuff…;

  3. Sniffer says:

    Just wanted to echo codinghobbit’s comment. This is an awesome resource – very entertaining and has also helped me get an idea of mine off of the ground.

    Good skills!

  4. Evan says:

    Thanks, Sniffer and Codinghobbit. I really appreciate it! Because, sometimes, it’s nice to know that I’m not talking to a wall. :)

    Sorry, btw, for the delay on new posts. I’m looking for a new place to live in (or near) Honolulu, so that (plus work) is sucking up all of my precious princess time.

  5. [...] Some of you might have died between Part 22 and Part 23. That’s okay. For those of you who are still sentient and coherent and death-free, you’ll remember that, in Part 22, we set up our ViewModel layer, and we mapped our FoodAdd ViewModel to our Model Food class (which was autogenerated by Linq 2 SQL) via Automapper. Remember? If not, go ahead and take a stroll down memory lane. [...]

 

Leave a Reply