Continuando a série sobre ASP.NET MVC Model Binding iniciada <aqui>, neste post mostrarei outros dois tipos de binding suportados pelo default model binder: binding de arrays/collections e o binding de arquivos enviados (upload).

Binding de arrays e collections

O default model binder é esperto o suficiente para saber fazer o binding de dados vindos de vários campos com o mesmo nome.

Imagine que iremos postar informações de 3 campos de mesmo nome:

....
<input id="pessoa1" type="text" name="pessoas" />
<input id="pessoa2" type="text" name="pessoas" />
<input id="pessoa3" type="text" name="pessoas" />
....


Podemos, então, receber esses dados em uma action de várias formas. Como um IList<string>:

[HttpPost]
public ActionResult Salvar(IList<string> pessoas) { //... }

Ou como um List<string>:

[HttpPost]
public ActionResult Salvar(List<string> pessoas) { //... }

Ou ainda como string[]:

[HttpPost]
public ActionResult Salvar(string[] pessoas) { //... }

Simples e flexível, não é?

Podemos fazer o mesmo com tipos customizados, sem problemas:

@using MvcModelBinding.Models
@model IList<Contato>
<h2>Contatos</h2>
@using (Html.BeginForm("Salvar", "Contato"))
{
   for (var i = 0; i < Model.Count; i++)
   {
      @:Nome: @Html.TextBoxFor(m => m[i].NomeCompleto)
   }
   <input type="submit" value="salvar" />
}

No exemplo acima usamos o tipo “Contato” criado na parte 1 desta série para renderizar diversos inputs para o campo “NomeCompleto”.

O HTML gerado pelo helper associará um prefixo para cada nome do input, tal como abaixo:

<input type="text" name="[0].NomeCompleto" value="JOSE DA SILVA" />
<input type="text" name="[1].NomeCompleto" value="MARIA DA SILVA" />
<input type="text" name="[2].NomeCompleto" value="JOAO DOS SANTOS" />

(Estou assumindo que havia 3 contatos na lista, com os nomes completos acima.)

E então, na action, recebemos os dados como uma coleção de contatos:

[HttpPost]
public ActionResult Salvar(IList<Contato> x) { //... }

Pelo fato de passarmos uma coleção como parâmetro da action (IList<Contato>), o default model binder irá procurar por valores de cada campo do tipo “Contato”, que esteja prefixado por um índice, isto é, [0].NomeCompleto, [1].NomeCompleto e assim por diante.

Sendo assim, o nome da coleção passa a ser irrelevante (usei o nome de “x” para deixar isso bem explícito). Basta você garantir que, nos nomes dos inputs, estejam corretos os prefixos e os nomes das propriedades do objeto.

Ainda falando de binding de coleções, é possível nomear os prefixos ao invés de utilizar índices, por exemplo, [contato1].NomeCompleto ao invés de [0].NomeCompleto, além de fazer o binding para um Dictionary ao invés de List, mas para não alongar demais este post, deixarei essas duas particularidades para vocês pesquisarem.

Upload de arquivos

Para fazermos o binding de um arquivo (upload), basta recebermos um parâmetro do tipo HttpPostedFileBase em nossa action:

[HttpPost]
public ActionResult Upload(HttpPostedFileBase arquivo) { //... }

No entanto, para que seja enviado o arquivo em si, ao invés de meramente seu nome, precisamos definir no formulário o atributo enctype (isto é uma característica dos browsers e nada tem a ver com o ASP.Net MVC):


<form action="@Url.Action("Upload")" method="post" enctype="multipart/form-data">
<input type="file" name="arquivo" />
<input type="submit" />
</form>

Mais uma vez, não devemos esquecer da convenção de nome, portanto, o nome do parâmetro da action deve ser o mesmo nome dado ao input do tipo “file” (no exemplo, chamado de “arquivo”).

CONCLUSÃO

Nesta segunda parte da série sobre Model Binding, vimos mais dois recursos do default model binder, que é capaz de fazer corretamente o binding de arrays, coleções e arquivos.

Até agora, vimos que todo o processo é realizado automaticamente: recebemos os dados via parâmetro e o action invoker “se vira” para usar o model binder e “preencher” os parâmetros corretamente com os dados vindos da  requisição.

No próximo post, veremos como ativar manualmente o processo de model binding!
_________________________________________________________________

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)