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.
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.
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).
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:
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.
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.
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.
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.
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.
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.
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.
I was working with a fresh install of Windows Server 2008 when I noticed a new parameter in Robocopy's usage output:
/MT[:n] :: Do multi-threaded copies with n threads (default 8).
n must be at least 1 and not greater than 128.
This option is incompatible with the /IPG and /EFSRAW options.
/MT is available in both 2008 and Win7. I did an informal benchmark against 12 GB of data spread over 300 files. The copy source was on the other end of a 100Mb switch.
With /MT:8 robocopy ran for 16 minutes and 24 seconds (984s).
With 1 thread robocopy ran for 18 minutes and 45 seconds (1125s).
7 threads yielded a savings of 12%.
I thought the copy operation would be 99% I/O bound with only 300 files to move, but I suspect the savings might be even more significant with the same data spread over 3,000 or 30,000 files.