A Mágica de Model Binder no MVC e Web API

Disponível também em inglês

Uma das coisas mais interessantes que já vi foi o tal do Model Binder e o objetivo desse artigo é demonstrar como criar uma classe com essa característica para usar tanto no MVC como no Web API.

Model Binder ou Model Binding é um mecanismo para popular (Binding) um objeto (Model) a partir de dados disponíveis em uma solicitação Request do navegador.

Overview do Model Binder:

O Model Binding já acontece na sua aplicação!

Quando você usa MVC, por exemplo, e faz um POST de um formulário, o MVC pega todos esses dados do formulário e popula um objeto prontinho e fresquinho automaticamente, disponibilizando a você toda vez que ele encontra esse objeto em um parâmetro, nos métodos ActionResult, veja um exemplo mais prático:

Imagine a URL “/clientes/salvar” no MVC para receber POST de um formulário. O método ActionResult no MVC seria assim:

[HttpPost]
public async Task<ActionResult> Salvar(ClienteViewModel viewModel)
{
    return Content("teste");
}

 
Como Criar um Banco de Imagens em MVC
 

No código acima, o MVC irá popular o parâmetro viewModel do método Salvar com todos os dados que vieram no POST.
 

Objetivos desse artigo:

Para esse artigo, o que precisaremos?

1 – Um projeto web para as plataformas MVC + Web API que você poderá criá-lo a partir do Visual Studio 2015 mesmo.

Ou se preferir você pode usar o Visual Studio 2017, mas dê uma olhada no UNBOXING VS2017 que escrevi com minhas primeiras impressões da nova IDE e decida se realmente precisa usar o 2017.

2 – Uma classe que implementará as interfaces de Binding para ambas as plataformas acima.
3 – Configurar a classe Model Binder nessas mesmas plataformas.
 

Qual é o objetivo da solução?

– Retornar informações sobre o ambiente do usuário logado, URL que foi solicitada, credenciais, informações de browser e outras coisas.
 

Classe Model Binder:

public class EnvironmentInfoModelBinder : System.Web.Mvc.IModelBinder, System.Web.Http.ModelBinding.IModelBinder
    {
        ///<summary>
        /// MVC version
        /// </summary>

        /// <param name="controllerContext"></param>
        /// <param name="bindingContext"></param>
        /// <returns></returns>
        public object BindModel(System.Web.Mvc.ControllerContext controllerContext,
            System.Web.Mvc.ModelBindingContext bindingContext)
        {
            var info = new Models.EnvironmentInfo();
            info.RequestedUrl = controllerContext.RequestContext.HttpContext.Request.Url.ToString();
            info.UserId = GetLoggedUser();

            // you also can get form/request properties

            return info;
        }

        ///<summary>
        /// WEB API version
        /// </summary>

        /// <param name="actionContext"></param>
        /// <param name="bindingContext"></param>
        /// <returns></returns>
        public bool BindModel(System.Web.Http.Controllers.HttpActionContext actionContext,
            System.Web.Http.ModelBinding.ModelBindingContext bindingContext)
        {
            var info = new Models.EnvironmentInfo();
            info.RequestedUrl = actionContext.Request.RequestUri.ToString();
            info.UserId = GetLoggedUser();

            // you also can get form/request properties

            bindingContext.Model = info;

            return true;
        }

        private string GetLoggedUser()
        {
            //just a sample
            return "3242423423";
        }
    }

Tanto o MVC como Web API entendem uma classe Model Binder quando há implementação da interface IModelBinder. Os métodos BindModel demonstrados acima disponibilizam todo o Contexto, Controller e Request para você brincar e acessar praticamente qualquer coisa no ambiente Server.

Para que o MVC ou Web API populem o objeto “EnvironmentInfo” com informações do ambiente do usuário logado, é ncessário registrar a classe acima na aplicação web.

Configuração da classe para MVC (Global.asax):

protected void Application_Start()
{
   ModelBinders.Binders.Add(typeof(Models.EnvironmentInfo), new Binders.EnvironmentInfoModelBinder());
}

Configuração da classe para Web API (WebApiConfig.cs):


public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services

        config.BindParameter(typeof(Models.EnvironmentInfo), new Binders.EnvironmentInfoModelBinder());
    }
}

Uso no Controller do MVC:

public ActionResult Index(Models.EnvironmentInfo environmentInfo)
{
  return View();
}

Uso no Controller do Web API:

public IHttpActionResult Get(Models.EnvironmentInfo environmentInfo)
{
   var result = new
   {
     EnvironmentInfo = environmentInfo
   };

   return Ok(result);
}

 

E a mágica?

Ainda falando sobre a mágica, o .NET tentará popular o objeto com informações do Request que ele tentará encontrar na ordem em:

1 – Request.Form – Formulários.
2 – RouteData.Values – Dados nas Rotas.
3 – Request.Querystring – Dados na querystring na URL.
4 – Request.Files – Dados de arquivos.

Tanto é que, se você tiver uma URL com o formato “/{controller/{action}/{id}” por exemplo “/clientes/salvar/39349” e usar o nome “id” no parâmetro de um método ActionResult, será retornado o valor 39349.

public ActionResult Index(string id)
{
    return Contet("vai retornar 39349");
}

Quem fará isso é o mecanismo Default de Binding do .NET.
 

Bom por hoje é isso. Espero que tenha ajudado.

A Mágica de Model Binder no MVC e Web API

Model Binder no MVC e Web API: Perguntas, sugestões ou críticas são bem vindas. Boa sorte!

Faça download completo do código fonte no github.
Sobre o Autor:
Trabalha como arquiteto de soluções e desenvolvedor, tem mais de 18 anos de experiência em desenvolvimento de software em diversas plataformas sendo mais de 16 anos somente para o mercado de seguros.
Revisado por:
Apaixonado por tecnologia e sempre disposto a encarar novos desafios, atualmente trabalho focado em aplicações web e mobile com a plataforma .NET, e me aventurando nas diversas linguagens, desafios e experiências que a área nos proporciona.