ASP.NET MVC Model Binding (parte 1 – DefaultModelBinder)

Neste post, iniciarei uma série sobre o mecanismo do ASP.NET MVC conhecido por Model Binding, mostrando suas principais características. Nesta primeira parte, a intenção é fazê-lo entender o que é o model binding, como funciona o binder default do MVC (DefaultModelBinder) e como ele facilita nossa vida.

O QUE É MODEL BINDING?

Model Binding é o processo de criar objetos .Net a partir de dados enviados pelo browser. Mesmo sem saber, estamos usando Model Binding toda vez que implementamos actions que recebem parâmetros.

Toda vez que uma requisição do tipo “/SeuController/SuaAction/121” é recebida, o framework MVC precisa tratar essa requisição de forma que possa passar valores apropriados nos parâmetros das actions.

De forma sucinta, esse tratamento inicia-se com o componente action invoker, que, como o próprio nome diz, é o responsável por invocar action methods. Antes de chamar a action, o action invoker verifica cada parâmetro e encontra o model binder correspondente para cada tipo de parâmetro.

Todo model binder implementa a interface IModelBinder, definida abaixo:

public interface IModelBinder
{
    object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext);
}

Na action abaixo, o action invoker irá procurar pelo model binder responsável por recuperar tipos inteiros (Int32) e chamar seu método BindModel para recuperar o valor do inteiro “id”.

public ViewResult Cliente(int id)
{
    //obter cliente pelo id
    //....
    return View(cliente);
}

DEFAULT MODEL BINDER

O framework MVC já possui seu próprio model binder, o objeto DefaultModelBinder, que é usado pelo action invoker sempre que um binder customizado para um determinado tipo não for encontrado.

O default model binder procura por dados em quatro lugares, na ordem abaixo:

1. Request.Form
2. RouteData.Values
3. Request.QueryString
4. Request.Files

Isto é, ao receber um parâmetro de nome “id”, o default binder procurará por Request.Form[“id”], RouteData.Values[“id”], etc. A busca se encerra assim que o valor for encontrado em um desses locais.

Embora uma aplicação possa ter inúmeros model binders, o DefaultModelBinder é muito poderoso, fazendo a conversão de dados para tipos primitivos e complexos, arrays, collections, além de ser capaz de receber arquivos via upload. Sendo assim, grande parte de uma aplicação ASP.Net MVC (ou 100% dela) fará uso exclusivo da classe DefaultModelBinder.

Binding de tipos simples

Processo já mostrado acima no action method que recebe um inteiro. O DefaultModelBinder é capaz de fazer o binding para qualquer tipo primitivo (int, string, DateTime, double, etc..).

Binding de tipos complexos

Em alguns casos, fica ruim passarmos uma série de parâmetros para a action method. Para simplificar, podemos encapsular os dados da requisição em uma classe e passar este tipo na action method.

Vamos tomar por exemplo a seguinte view tipada:


@model Contato
<h2>Contato</h2>
@using (Html.BeginForm())
{
    <div>Nome: @Html.TextBoxFor(c =&gt; c.NomeCompleto)</div>
    <div>Fone: @Html.TextBoxFor(c =&gt; c.Fone)</div>
    <div>E-mail: @Html.TextBoxFor(c =&gt; c.Email)</div>
    <div></div>
}

O tipo “Contato” utilizado na view encapsula as informações que iremos postar e não passa de uma classe bem simples:


public class Contato
{
    public string NomeCompleto { get; set; }
    public string Fone { get; set; }
    public string Email { get; set; }
}

E recebemos o objeto Contato na action method:


[HttpPost]
public ActionResult Editar(Contato contato)
{
    // aqui temos disponível o objeto "contato" com todos os seus atributos
    // devidamente preenchidos (contato.NomeCompleto, contato.Fone, contato.Email)

    return RedirectToAction("Index");
}

Para fazer essa “mágica”, o default model binder verifica as propriedades do objeto Contato. Se a propriedade é um tipo básico do .Net, o binder procura por um dado passado na requisição que tenha o mesmo nome da propriedade (por exemplo, “NomeCompleto”) e preenche a propriedade com o valor recebido.

Caso o tipo da propriedade for um outro tipo complexo – por exemplo, se tivéssemos um “Endereco” na classe “Contato” – o binder faria a verificação das propriedades desta classe aninhada da mesma forma.

Em outras palavras, se “Contato” tivesse uma propriedade de nome “EnderecoResidencial” do tipo “Endereco”:

public class Contato
{
    // demais propriedades

    public Endereco EnderecoResidencial { get; set; }
}

E “Endereco” tivesse as seguintes propriedades:

public class Endereco
{
    public string Rua { get; set; }
    public string Bairro { get; set; }
    public string Cidade { get; set; }
}

O default model binder procuraria por “EnderecoResidencial.Rua” e assim por diante.

Quando utilizamos os Html.Helpers, os atributos “name” do HTML são gerados na forma que o binder espera, ou seja, quando fazemos @Html.TextBoxFor(c => c.EnderecoResidencial.Rua), teremos um <input> de name “EnderecoResidencial.Rua”.

Portanto, devemos ter atenção com os nomes quando estamos escrevendo o HTML “na mão”.

CONCLUSÃO

Vimos neste post uma introdução ao mecanismo de Model Binding e ao default model binder, que conta com uma convenção de nome para encontrar os dados de uma requisição HTTP e convertê-lo para o tipo desejado.

Com Model Binding, ainda podemos limitar quais propriedades queremos que o binder verifique, podemos definir prefixos para os nomes dos campos, etc.

O Model Binding facilita muito no processo de obtenção dos dados, evitando que os desenvolvedores tenham que “investigar” manualmente nas coleções Request.Form, Request.QueryString, etc. (por consequência deixando o código mais limpo).

No próximo post, falarei de outros tipos de binding suportados pelo default model binder.
_________________________________________________________________

Este artigo faz parte da série:
1) ASP.NET MVC Model Binding (parte 1 – DefaultModelBinder)
2) ASP.NET MVC Model Binding (parte 2 – outras formas de binding)
3) ASP.NET MVC Model Binding (parte 3 – binding manual)
4) ASP.NET MVC Model Binding (parte 4 – custom binders)

12 comentários em “ASP.NET MVC Model Binding (parte 1 – DefaultModelBinder)

Adicione o seu

  1. Parabéns Robson, muito bom esse post!! Mostrou de forma bem clara como o model binding trabalha… Isso ae!!

    Curtir

Participe! Vamos trocar uma ideia sobre desenvolvimento de software!

Blog no WordPress.com.

Acima ↑