Notes on Templates and Data Annotations in MVC 2

Sunday, July 25, 2010 by K. Scott Allen
2 comments

Brad Wilson has an excellent series of 5 blog posts on model metadata and templates you can use to get started with templates and metadata in ASP.NET MVC 2. Here are a couple notes I've made around some of aspects that commonly confuse developers (including me, it seems).

1. Although most of the metadata attributes live in the System.ComponentModel.DataAnnotations namespace, there are a few exceptions. If you aren't seeing something you need in Intellisense, then try adding System.ComponentModel (for the popular DisplayName attribute) and System.Web.Mvc (for the popular HiddenInput attribute).

2. Some of the confusion around data annotations exists because the MVC runtime doesn't recognize every data annotation attribute built into .NET. For example, using [Editable(false)] is tempting, but you'll find it doesn't have any impact in model binding, validation, or templating. The built-in templates respect 7 data annotation attributes:

  • DisplayColumn
  • HiddenInput
  • UIHint
  • DataType
  • DisplayFormat
  • ScaffoldColumn
  • DisplayName

3. There are two additional attributes the default model metadata provider will consume:

  • ReadOnly
  • Required

However, the built-in templates do not make use of the information from these attributes. For example, you can apply [ReadOnly(true)] to a property, but you'll find the default templates in use by helpers like Html.EditorForModel will still show a textbox input for the user to enter a value. If you want to get rid of the input with EditorForModel you'll need a custom template, or you'll need to use [ScaffoldColumn(false)].

Note the default model binder does respect the ReadOnly attribute, so it won't move a value into a property with [ReadOnly[false)]. Also, the built-in validation logic respects the Required attribute. These attributes definitely have value in an MVC app, but they won't influence the UI rendered by the default templates.

Prototypes and Inheritance in JavaScript

Thursday, July 22, 2010 by K. Scott Allen
8 comments

Forget everything you know about object-oriented programming. Instead, I want you to think about race cars. Yes – race cars.

That's the intro for my latest article @ Script Junkie - Prototypes and Inheritance in JavaScript. I hope you enjoy reading it.

 

Delegated Model Binding

Sunday, July 18, 2010 by K. Scott Allen
1 comment

In the last post we saw the recursive nature of the default model binder in MVC. Now, let's look at the following class:

public class User
{
    public string Name { get; set; }
    public string Email { get; set; }
    
    /* 
     * bunch more simple stuff 
     */

    public AuthorizationClaims AdditionalClaims { get; set; }
}

Imagine AdditionalClaims are something that the default model binder will not understand. For whatever reason, you'll need to use a custom model binder to pull data from the request environment and into the claims property. If you don't know how the default model binder works, you might think "because the model binder doesn't understand part of this model, I'll have to write a model binder for the whole model", and do this:

public class UserModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext,
                            ModelBindingContext bindingContext)
    {
        // stuff ...
    }
}

And register the class during application startup:

ModelBinders.Binders.Add(typeof (User), new UserModelBinder());

This probably isn't the approach you want to use for a couple reasons:

1) The model binder is not only responsible for claims, but also for all the other properties (name, email, etc).

2) You've only solved the problem of binding claims in a single model type. That's fine if AuthorizationClaims only appears in a single model type, but maybe it doesn't (and maybe it won't in the future).

Remember the default model binder delegates the work of binding each property. Knowing how the default model binder works, it's easier to focus in on just the piece you need to customize.

public class AuthorizationClaimsModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext,
                            ModelBindingContext bindingContext)
    {
        /* implementation details */
    }
}

And:

ModelBinders.Binders.Add(typeof(AuthorizationClaims),
                new AuthorizationClaimsModelBinder());

Now the claims binding will work anywhere - even when claims are nested in another type, and it doesn't require code changes in the future.

However ...

Isn't there always a catch?

In order for the default model binder to delegate the work of creating an AuthorizationClaims it first has to think there is an AuthorizationClaims available. It does this using "value providers" and "prefixes". We'll talk about these concepts and how to implement the model binder in a future post (but not right away - too much model binding at once is boor - riiiing).

Recursive Model Binding

Thursday, July 15, 2010 by K. Scott Allen
1 comment

In the last post we saw how a model binder has to show up for work even when all we need is a simple int parameter on an HTTP GET request.

Now it's time for a pop quiz!

Given this route definition:

routes.MapRoute(
    "SearchRoute",
    "Home/Browse/{category}",
    new {controller = "Home", action = "Browse"});

And this class definition:

public class BrowseRequest 
{
    public int StartYear { get; set; }
    public string Manufacturer { get; set; }
    public string Category { get; set; }
    public string Controller { get; set; }
    public string Action { get; set; } 
}

And given this request arrives as a GET:

http://server/home/browse/appliances?startyear=2009&manufacturer=GE

.. at this method of HomeController:

public ActionResult Browse(BrowseRequest search)
{
    // ...
    return View();
}

Then what will BrowseRequest look like?

Answer:

The DefaultModelBinder will create a new BrowseRequest object and populate it with the following values:

  • Action = "browse" (from route data)
  • Category = "appliances" (from route data)
  • Controller = "home" (from route data)
  • Manufacturer = "GE" (from the query string)
  • StartYear = 2009 (from the query string)

The default model binder is adept at building up entire objects using information it finds in the request environment. Binding removes all the clumsy code you would otherwise write to find and shuffle data around. The default model binder can even build up collections and complex object graphs

It's Recursive (Sort Of)

When the MVC runtime realizes it needs a BrowseRequest object, it looks for a model binder for the BrowseRequest type (a topic for a future post) and invokes the binder's BindModel method (it's part of the IModelBinder contract that every model binder must implement).

If the binder in question is the DefaultModelBinder, then it doesn't just jump in and start setting properties in one operation. The default model binder's brain works something like this*:

Default Model Binder: "Hmm, this looks like a complex thing with lots of properties. I'm going to loop through each property and tell some other model binder to do this work for me. Let's start with this Manufacturer property - it's of type string. Hey! MVC! Give me the model binder for string types!"

MVC Runtime: "Here is the model binder. Thank you for asking, please come again." 

Default Model Binder: "I will setup a new binding context for this binder and call BindModel --"

     Default Model Binder: "Hey - I'm binding a string named Manufacturer. Found it! Done! Pop!"

Default Model Binder: " -- and now that manufacturer is done, let me look at this StartYear of type int. Hey! MVC! Give me the model binder for int types!"

MVC Runtime: "Here is the model binder. Thank you for asking, please come again."

And this conversation continues until the binder visits all the properties. When you ask the model binder to bind a simple primitive type like string and int - it will do so, but anything more complex** and the binder effectively breaks up the big job into a series of smaller jobs. It turns out that most of the time the default model binder is recursively calling itself to do these smaller binding jobs, but the flow doesn't have to run this way.

Why Is This Important?

If you want to plug in a custom model binder this recursive behavior is important to understand. You can verify that binding a BrowseRequest object takes 6 calls to BindModel using a debugger and the following code:

public class MyModelBinder : DefaultModelBinder
{
    public override object BindModel(
        ControllerContext controllerContext, 
        ModelBindingContext bindingContext)
    {
        // set a break point inside this method
        return base.BindModel(controllerContext, bindingContext);
    }
}

And put the following into Application_Start:

ModelBinders.Binders.DefaultBinder = new MyModelBinder();

However, the default model binder doesn't know it's calling itself. It's just trying to delegate work to whatever model binder is registered for a given type. If you register a model binder for typeof(string) or typeof(int), the default model binder in this scenario would be calling into those other model binders.

In a future post we'll exploit this delegating behavior to simplify a binding scenario.

* There are a few simplifications made in this depiction. It's the essence that counts.

** There are always special cases - collections are an example of an exception to the this rule.

Hard Working Model Binder

Wednesday, July 14, 2010 by K. Scott Allen
2 comments

The job of a model binder in ASP.NET MVC is to take pieces of data in an HTTP request and place them into objects. It's easy to sense a model binder at work when you use one of the Update API's.

bool success = TryUpdateModel(movie); // here

// .. or ...

try
{
    UpdateModel(movie); // here, too!
}
catch (InvalidOperationException ex)
{
    // ... model binding errors ...
}

If the first line of code with TryUpdateModel could speak, it would say something like "Here is a movie. I want you to look around and find information to populate the movie. Go look in the posted form values, in the routing data picked out of the URL, and in the query string to see if you can find something called "Title". If you do find a title, move the value into the "Title" property of the movie. Do the same for "TagLine", "Summary", and the rest of my movie properties, and do it fast!".

Ok, it doesn't really say "do it fast", but we'd like to think it will be fast.

Conceptually, a model binder is a match maker who pairs things together based on their name.

Binding - Not Just For Models

unhappy by gagilas.The "model" part of the model binding name does lead to some confusion.

Don't tell the model objects this because they might get upset - but models aren't special.

A model binder can work against any type of object. The object doesn't have to be an official "model" or even complex type. In fact, a model binder might be at work in more places than you suspect.

Take, for example, the following HTTP GET request.

http://server/home/index/3

or

http://server/home/index?id=3

Assuming you have the default routing rule in place, a model binder runs to execute this action:

public ActionResult Index(int id)
{
    // ...
}

When an action is invoked, the action invoker sees the id parameter and asks a model binder to bind the parameter. Unless you've configured a different model binder, then it is the MVC DefaultModelBinder that will locate the value for "id". The model binder will find this value in the routing data (if the URL used is index/3), or it will find it in the query string (if the URL is index?id=3).

In summary, model binding isn't just for updating model objects in an HTTP POST. There is a model binder at work for simple parameter types like integers during mundane HTTP GET requests. We'll need to remember this fact when we look at more characteristics of these hard-working, recursive MVC denizens in a future post.

Ruby: initialize and super

Tuesday, July 13, 2010 by K. Scott Allen
8 comments

One of the reasons to like Ruby if you come from a C#/C++/Java background is how certain constructs will tend to "just make sense" even though Ruby will throw in a twist here and there.

Consider the case of inheritance and initialize methods.

class Employee < Person
end

emp = Employee.new

Let's say you run the code and get an error on the line of code creating the Employee object : "wrong number of arguments". Seems odd, because Employee doesn't look like it needs an argument for creation, but then you poke around and find the definition for Person (the base class).

class Person    
    def initialize(name)
        @name = name
    end    
end

Ah, so we need a name to build a person object. The C# developer might instantly think of this scenario:

class Person
{
    public Person(string name)
    {
        this.name = name;
    }

    string name;
}

class Employee : Person
{
}

 

With C# you have to give Employee a constructor that will forward a name parameter to the base constructor.

class Employee : Person
{
    public Employee(string name) : base(name)
    {            
    }
}

In Ruby you can take this approach, too. It's a good approach if you need to perform some extra initialization for employees, like require a salary figure.

class Employee < Person
    def initialize(name, salary)
        super(name)
        @salary = salary
    end
end

emp = Employee.new("Chuck", 100)

It's Ruby's super keyword that acts like the base keyword in C#. The twist here is how Ruby will just make things work in the trivial case.

class Employee < Person
end

emp = Employee.new("Chuck")

In this code, "Chuck" will arrive at the initialize method of Person without any explicit code from us.

You might call it magic, or you might call it wonderful.

OData and Ruby

Sunday, July 11, 2010 by K. Scott Allen
0 comments

The Open Data Protocol is gaining traction and is something to look at if you expose data over the web. .NET 4 has everything you need to build and consume OData with WCF Data Services. It's also easy to consume OData from outside of .NET - everything from JavaScript to Excel.

I've been working with Ruby against a couple OData services, and using Damien White's ruby_odata. Here is some ruby code to dump out the available courses in Pluralsight's OData feed.

require 'lib/ruby_odata'

svc = OData::Service.new "http://www.pluralsight-training.net/Odata/"
svc.Courses
courses = svc.execute
courses.each do |c|
   puts "#{c.Title}"
end

ruby_odata builds types to consume the feed, and also maps OData query options.

svc.Courses.filter("substringof('Fundamentals', Title) eq true")
fundamentals = svc.execute
fundamentals.each do |c|
    puts "#{c.Title}"
end

There is one catch - the Pluralsight model uses inheritance for a few of the entities:

<EntityType Name="ModelItemBase">
    <Property Name="Title" Type="Edm.String" ...="" />
    <!-- ... -->
</EntityType>
<EntityType Name="Course" BaseType="ModelItemBase">
    <Property Name="Name" Type="Edm.String" Nullable="true" />
    <!-- ... -->
</EntityType>

Out of the box, ruby_odata doesn't handle the BaseType attribute and misses inherited properties, so I had to hack around in service.rb with some of the Nokogiri APIs that parse the service metadata (this code only handles a one level of inheritance, and gets invoked when building entity types):

def collect_properties(edm_ns, element, doc)
    props = element.xpath(".//edm:Property", "edm" => edm_ns)
    methods = props.collect { |p| p['Name'] }
    unless element["BaseType"].nil?
        base = element["BaseType"].split(".").last()
        baseType = doc.xpath("//edm:EntityType[@Name=\"#{base}\"]",
                             "edm" => edm_ns).first()
        props = baseType.xpath(".//edm:Property", "edm" => edm_ns)
        methods = methods.concat(props.collect { |p| p['Name']})
    end
    return methods    
end

The overall Ruby <-> OData experience has been quite good.

by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!