Tag Archives: aspnetmvc

Dictionary Model Binder in ASP.NET MVC2 and MVC3

In a decidedly typical turn of events, Microsoft changed the API of BindModel in ASP.NET MVC 2 such that it breaks DefaultDictionaryBinder. No longer can you enumerate through the ValueProvider, instead you can only Get a value which you know the name of. I’ve updated the code to work with MVC2 and also tested it with the new MVC 3 RC.

The code is compatible with ASP.NET MVC 1, 2 and 3. To use it for ASP.NET MVC 1, just set the conditional compiler directive ASPNETMVC1 and it will enable the MVC 1 code, otherwise it will work with MVC version 2 and 3.

The code is now up at github: DefaultDictionaryBinder.cs.

There’s also an example MVC3 project showing the basic functionality of the Dictionary Binder: link

Verifying Anti-Forgery Token for Form POST only

As many of you know, the ASP.NET MVC Anti-Forgery token helps thwart Cross Site Request Forgery attacks. Any site that uses authenticated sessions (99% of web apps) should use similar mechanisms so these attacks cannot occur.

Very often, I would write GET and POST actions in the same method. This allows fall through to that same code we used for GET request if POST validation fails, ensuring consistency.
[csharp]
public ActionResult EditPerson(Person person)
{
if (Request.HttpMethod == "POST" && ModelState.IsValid)
{
// do edit person…

return RedirectToAction("Index");
}

// do get person

return View(person);
}
[/csharp]
If I use that sort of paradigm, then the [VerifyAntiForgeryToken] attribute would block both GET and POST requests when the token is not supplied. I want the token to be only verified when I POST. Since ASP.NET MVC is extensible, the normal way to go about that would be modify the behaviour of [VerifyAntiForgeryToken] by subclassing. Unfortuantely, VerifyAntiForgeryTokenAttribute is sealed which means it can’t be inherited from. Luckily, borrowing from the same trick that Http*Base classes use to combat sealed Http* classes, we can just create a new attribute that wraps the old attribute, implementing the same members and proxying the calls back to the wrapped base class. That’s exactly what I did and it works quite well. The result is [ValidateAntiForgeryTokenOnPost] which will only verify the form anti-forgery token on a POST request:
[csharp]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class ValidateAntiForgeryTokenOnPostAttribute : FilterAttribute, IAuthorizationFilter
{
private ValidateAntiForgeryTokenAttribute _wrapped;
public ValidateAntiForgeryTokenOnPostAttribute()
{
_wrapped = new ValidateAntiForgeryTokenAttribute();
}

public string Salt { get { return _wrapped.Salt; } set { _wrapped.Salt = value; } }

public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.HttpMethod == "POST")
{
_wrapped.OnAuthorization(filterContext);
}
}
}
[/csharp]
This will teach those sealed classes!

An intuitive Dictionary Model Binder for ASP.NET MVC

The other day I was working on an ASP.NET MVC website and came across a need to post an array from the browser into the web app. The framework comes with something called a Model Binder that automagically converts submitted form data into action parameters of the controller. For example, if we have form submitted data such as
person.FirstName=John&person.LastName=smith
for a theoretical model class ‘Person’, and
[csharp]public ActionResult SavePerson(Person person)[/csharp]
as the action method signature, SavePerson will be executed with the parameter equivalent to
[csharp]new Person() { FirstName = "John", LastName = "Smith" }[/csharp]

The default model binder is pretty powerful, using reflection to dig out and assign all the fields. It also supports arrays and dictionaries, but with big limitations. The array must start at 0 and be unbroken. That is understandable for arrays, but what if you had a dictionary? Surely it can start at any position? Not so. The dictionary has even more obscure requirements, with the need to specify explicit .Key and .Value parameters in your form submission. For example:
dict[0].Key=mykey&dict[0].Value=myvalue
This represented extra work to generate the form on the client side. I just want to input something more intuitive like:
dict[mykey]=myvalue
The ASP.NET MVC framework is highly extensible. It allows you to define your own custom model binder so that’s exactly what I did. Inheriting off DefaultModelBinder, I created DefaultDictionaryBinder that overrode the BindModel method and intercepts when a IDictionary<,> class is being bound.

The code is now up at github: DefaultDictionaryBinder.cs. Note that if you are using this on ASP.NET MVC 1, please define the macro ASPNETMVC1. If you are using it with MVC 2 or MVC 3, it should work as is.

To use, you have to override the default model binder. In global.asax.cs in Application_Start(), add the line:
[csharp]
ModelBinders.Binders.DefaultBinder = new DefaultDictionaryBinder();
[/csharp]

The code is very flexible, only requiring the dictionary key to be of a basic type convertible from string, ie. Dictionary or Dictionary. The value can be any object that is able to be bound by the default model binder.
An example follows:
If your form input is
persons[3].FirstName=John&persons[3].LastName=Smith&persons[4].FirstName=Jane&persons[4].LastName=Doe&
and our action signature
[csharp]public ActionResult SavePersons(Dictionary<int, Person> persons)[/csharp]
the persons parameter would be
[csharp]
new Dictionary<int, Person>() {
{ 3, new Person() {"John", "Smith"} },
{ 4, new Person() {"Jane", "Doe"} },
}
[/csharp]

Simple and intuitive.

Download: DefaultDictionaryBinder.cs Simple Example Project (ASP.NET MVC 3 required)