Skip to content
This repository has been archived by the owner on Apr 29, 2020. It is now read-only.

Latest commit

 

History

History
72 lines (55 loc) · 4.63 KB

Parameter-Binding.md

File metadata and controls

72 lines (55 loc) · 4.63 KB

Parameter Binding

Motivation

Route parameter constraining and binding are two separate mechanisms. First, Regex constraints are executed when routing tries to find a route that matches. Second, before action invocation, Model Binding converts the route parameter (usually a string) to the appropriate type. Unless there's a custom model binder configured, this usually falls back to System.Convert.

This is not desirable for a number of reasons, specially when dealing with non-string parameters:

  • A Regex constraint might not be 100% accurate and could match values that would later be rejected by Model Binding. There's clearly no need for two parsing mechanisms.
  • Regex constrains are also executed on URL generation, even if the value provided is already of the same type used in the action method. This is clearly unnecessary and inefficient.

What about Model Binders as constraints?

If model binders are used to parse route parameters it would seem logical to reuse them for constraints. However, there are several issues associated with this idea:

  • Model binders depend on ControllerContext, which depends on RequestContext, which depends on RouteData. None of these are available when route constraints are executed.
  • Model binding is too powerful for simple types. It depends on ModelMetadata, IValueProviders, it supports prefixed parameters, etc. This power and complexity is not needed for parsing route parameters.
  • MVC and Web API have different model binding APIs, you'd need to write two different binders to support both frameworks.

Parameter Binding is introduced to overcome all of these issues.

How it works

This is the definition of the ParameterBinder class:

public abstract class ParameterBinder {

   public abstract Type ParameterType { get; }

   public abstract bool TryBind(string value, IFormatProvider provider, out object result);
}

The ParameterType property declares which type the binder is meant for.

The TryBind method takes the string value of a route parameter and returns true if the bind is successful, or false if not, while also returning the bound value in the result output parameter. The value parameter is always a non-null, non-empty instance. The provider parameter is always CultureInfo.InvariantCulture.

How to use it

There are three ways to configure binders. The first way is by using the ParameterBinder attribute on the type.

The second way, which overrides the first, is using the ParameterBinders setting. By default it includes binders for Boolean, Guid, Decimal, Double, Single, SByte, Int16, Int32, Int64, Byte, UInt16, UInt32 and UInt64. You can add binders for other types, or override the built-in binders.

The third way, which overrides the first and the second, is using [FromRoute(BinderType)], which now can be used to specify either a model binder or parameter binder.