The Windup

It is very easy for a developer to use classes generated by their ORM of choice (such as Entity Framework) as data models in an ASP MVC application.  The reasons for doing so are straightforward.  If we didn’t reuse the classes, we would have to remake them. Creating a second class with essentially properties of the first class seems to defeat the purpose of code re-use.  As developers we’re trained to the point of rote to not like such patterns.  They create extra work and inefficiency.

The MVC model binder is advanced enough to be able to bind form data to complex EF objects. It is good enough at this to let Microsoft feel safe to let the default scaffolding inside Visual Studio generate CRUD methods in a controller around the class generated by the Entity Framework.  Between the framework and scaffolding, a developer can very easily and quickly set up a basic CRUD website around a database.

The Pitch

As an example, lets assume we have an extraordinarily simple User table with the following schema:

  • UserID
  • UserName
  • Password
  • IsAdmin

The resulting scaffolding would contain an Edit(User model) method that would receive form data, attach the model to the EntityContext, and save the changes.  Works like a champ.  Add on a simple business rule:

  • This application is not allowed to create admins

It would be very tempting to change the HTML or helper function to hide the IsAdmin parameter.  This would achieve the goal: the application’s UI does not allow someone to edit a User and change the IsAdmin state.  The problem is the model binder.  The cost we pay for having the binding happen under the hood is that the binder blindly attempts to match up as much as possible.  The presence of IsAdmin in the postback will force the binder to populate that property of a User object, and the controller method will blindly save the changes.  An astute user can edit the HTML in the browser to toggle this data manually, then save it on their own.  The binder processes the changed field, and the controller method does what it’s told to do.  A person promotes themselves to an admin with this application which is not supposed to let that happen.

This is the concept of over-posting.  The form contains more data than necessary to accomplish the necessary goals, thus exposing that extra data to outside modification.

The Hit

A straightforward way to combat this is biting the proverbial bullet and maintaining DTO (data transfer object) classes with only the properties necessary for managing data within the system.  This will allow continued use of MVC’s binding features while ensuring that only the necessary data is included with the form and sent back to the system.  The good news on this front is that there are some tools to help.

Enter AutoMapper.  AutoMapper provides the tools to turn the mapping of DTO to EF classes into a single line.  To better understand how it works, lets take a look at that User class generated by EF:

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Password { get; set; }
    public bool IsAdmin { get; set; }
}

This application will never need to change the IsAdmin property; we will need a DTO class to hide that property. This class would look very close to the original User:

public class UserDTO
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Password { get; set; }
}

The UserDTO class would then be the class we create controller methods around as well as use as a data model in views as necessary. What AutoMapper does is remove the need to write a User.FromDTO(UserDTO model) method, or other equivalent means to manually copy the properties accordingly. The first step in using AutoMapper is to define the relationship between a User and a UserDTO.  In this case, the relationship is straightforward: the properties of both classes have the same name and compatible types.  To define this relationship, insert the following code somewhere in the application’s startup:

Mapper.CreateMap<User, UserDTO>();

Later on in the application, when it is time to edit a user, the Edit() method and resulting view are build to use the UserDTO class instead of the User class. AutoMapper saves a bit of the gruntwork by taking care of the UserDTO creation. An example Edit(int id) method would look like this:

public ActionResult Edit(int id = 0)
{
    if (id < 1) RedirectToAction("Create");
    User u = db.Companies.Find(id);
    if (udto == null)
    {
        return HttpNotFound();
    }
    UserDTO dto = Mapper.Map<UserDTO>(u);
    return View(udto);
}

The mapping of the shared properties between the User and UserDTO class is handled by AutoMapper, leaving the developer more time to focus on the important parts of the function.

AutoMapper is available via NuGet, or you can click for more information.