ASP.NET MVC – Design de controllers – Parte 1

Numa aplicação Asp.net MVC ,controllers existem para responder qualquer requisição que um usuario faça através da interface de usuario.Qualquer interação entre a aplicação e o usuario é geralmente descrita como use-case.Como arquiteto,você começa a partir do user-case pra ter uma idéia clara das funções que devem estar disponiveis para o usuario na aplicação.

Sua próxima tarefa é simplesmente mapear funções para a classe controller.

Não existem razões técnicas que o impeçam de ter uma única classe controller que englobe toda a aplicação;e da mesma forma não existem razão técnicas que o impeçam,de ter uma classe controller para cada possível requisição.

Você está agora no momento de particionar o conjunto de funções num número balanceado de classes controller.Como você faz isso,depende das funções e mais o mais importante,da visão da aplicação que se origina do user-case.Como via de regra,você deve se preocupar em ter uma classe controller para cada entidade significante na solução da sua aplicação.

Num site comercial,é comum você encontrar use-cases que precisem de operações CRUD (Create,Read,Update,Delete) em clientes,pedidos,detalhes do pedido, e faturas.Você pode então iniciar com um OrderController para permitir que usuarios criem um novo pedido,assim como atualizar ou deletar pedidos.Fazendo isso,você deve estar focado nas necessidades da camada de apresentação,e colocar de lado,como irrelavente no momento,as necessidades da entidade modelo da camada de negócios.

Se você lida com pedidos,você provavelmente também lida com detalhes do pedido e produtos.Porém,apesar de Pedidos,Detalhes do pedido,e produtos serem bons candidatos a se tornarem membros do modelo de entidades (ou domain model,se você aplicar a metodologia domain-driven),somente Pedidos faz sentido como inspirador da criação de uma classe controller.A partir da perspectiva da interface de usuario,na verdade,um usuario irá enviar comandos somente para criar,atualizar ou deletar pedidos.Nesse caso,é OK ter um OrderController,mas não é OK ter um OrderDetailsController.Uma regra simples é a seguinte.

Ter um contoller para cada entidade de negócio que é diretamente exposta na camada de apresentação.

Esse poder ser apenas o primeiro passo,no entanto.

Suponha que um dos use-cases determine que você deva fazer com que os usuarios possam visualizar faturas.Um InvoiceController seria então util para servir as necessidade do usuario.Num site comercial,no entanto,provavelmente você vai disponibilizar uma seção de back-office para controle administrativo,como processamento de pedidos e faturas.Nesse caso,pode ser util tem uma classe controller distinta para suportar operações de back-office para pedidos e faturas.Outra regra simples é a seguinte:

Tenha uma classe controller para cada entidade da camada de negócio que é exposta diretamente na camada de apresentação e pra cada contexto operacional.

No fim das contas,o mapeamento de funções para controllers,e o subsequente mapeamento de métodos para controllers,certamente não é uma ciência exata.Porém,com a correta e sistemática aplicação dos principios da chave de design,você pode obter um design que seja aceitavel para todas as partes interessadas no projeto.O principio é o Single Responsibility Principle – SRP (Principio da Responsabilidade única).As duas regras simples citadas anteriormente fazem parte do SRP.

Mapeando comportamento de métodos

No todo, a parte mais complicada do processo de design é mapear as funções para os controllers.Depois de você ter estabelicido uma lista aceitavel de controllers,deve ficar claro quais métodos pertecem a quais controllers.Métodos de um controller são conhecidos como Actions – e o nome não poderia ser mais apropriado.Num controller,você tem um método para cada ação do usuario, o que acaba caindo na (única) responsabilidade do controller.

Como você codifica um método de um controller?O template de um método pode ser resumido no seguinte:

  • Recuperar dados de entrada – Um método pode obter argumentos de entrada de várias fontes:route values e coleções expostas pelo objeto Request.O ASP.NET MVC não impõe uma assinatura particular para métodos de um controller.Para testes,é preferivel que qualquer parametro de entrada seja recebido através da assinatura do método.Evite,se você puder métodos que recuperem parametros programaticamente através do objeto Request.Pré-condições também ajudam a garantir que não hajam valores incorretos passados nas camadas do sistema.
  • Realizar a tarefa – Nesse momento,o método realiza o seu trabalho baseado nos argumenos de entrada e nos resultados esperados.Na maioria das vezes,o método precisa interagir com a camada intermediária e qualquer dessas interações é feita através de serviços dedicados.Validações de valores calculados ocorrem também nesse estágio.
  • Preencher o View-Model – No fim da tarefa,qualquer valor que deva ser incorporado na resposta é adicinado ao view-model.O view-model pode ser um dicionario plano de key/value,ou um objeto strong-typed especifico daquela view.
  • Preparar o objeto result – Um controller não é responsável por produzir a resposta em si.Ele é responsavel,por disparar o processo que irá usar um objeto View distinto para renderizar o resultado para a saída.O método identifica o tipo da resposta (file,plain data,HTML,JavaScript,ou JSON) e prepara um objeto ActionResult de acordo.

Parece fácil de maneira geral?Bom,outro aspecto complicado é como você elabora o código que executa a tarefa.Mas isso fica para a próxima parte de design de controllers.

Até lá!

ASP.NET MVC Controllers

Entendendo Controllers

Controllers são responsáveis por respostas a requisições feitas em um website ASP.NET MVC.Cada requisição de um navegador é mapeada para um controller em particular.Por exemplo,imagine que você entre com a seguinte URL no seu navegador:

http://localhost:4656/Product/Index/3

Nesse caso,um controller chamado ProductController é chamado.Esse controller é responsável por gerar a resposta para a requisição do navegador.Por exemplo,o controller poderia retornar uma View em particular para o navegador ou poderia redirecionar o usuario para outro controller.

Veja abaixo o ProductController:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax; 

namespace MvcApplication1.Controllers
{
public class ProductController : Controller
{
//
// GET: /Products/

public ActionResult Index()
{
// Add action logic here
return View();
}

}
}

Como você pode ver acima,um controller é somente uma classe.Um controller é uma classe que deriva da classe base System.Web.Mvc.Controller.Como todo controller herda dessa classe base,um controller herda muitos métodos úteis gratuitamente.

Entendendo Actions

Uma Action é um método em um controller que é chamado quando você entra com uma URL particular no navegador.Por exemplo,a seguinte URL:

http://localhost:4656/Product/Index/3

Nesse caso,o método Index é chamado na classe ProductController.O método Index é exemplo de uma action.

Uma action deve ser um método público de um controller.Métodos C#,por padrão são privates.Perceba que qualquer método público em um controller é considerado uma action automaticamente (por isso você deve ser cuidadoso,pois esse método pode ser invocado por qualquer um no universo simplesmente digitando a URL correspondente no navegador).

Existem alguns outros requerimentos para uma action.Um método usado como action não pode ser sobreescrito.Também não pode ser static.Fora isso,você pode usar qualquer outro método como action.

Entendendo Action Results

Uma action retorna algo chamado action result.Uma action result é o que um controller retorna em resposta a uma requisição de um navegador.

O ASP.NET MVC framework contém vários tipos de action results:

  1. ViewResult – Representa HTML e markup
  2. EmptyResult – Representa resultado vazio
  3. RedirectResult – Representa redirecionamento para uma nova URL
  4. JsonResult – Representa um resultado JSON que pode ser utilizado numa aplicação AJAX
  5. JavaScriptResult – Representa um script JavaScript
  6. ContentResult – Representa um resultado em texto
  7. FileContentResult – Representa um arquivo que pode ser baixado (com conteúdo binário)
  8. FilePathResult – Representa um arquivo que pode ser baixado (com um path)
  9. FileStreamResult – Representa um arquivo que pode ser baixado (com um stream)

Todos esses Action Results herdam da classe base ActionResult.

Na maioria dos casos,uma action retorna um ViewResult.Por exemplo,o método Index abaixo retorna um ViewResult:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax; 

namespace MvcApplication1.Controllers
{
public class BookController : Controller
{

public ActionResult Index()
{
// Add action logic here
return View();
}

}
}

Quando uma action retorna um ViewResult um HTML é gerado para o navegador.O método Index acima retorna uma view chamada Index para o navegador.

Note que a action Index não retorna um ViewResult().Ao invés disso,o método View() da classe controller é chamado.Normalmente,você não retorna um action result diretamente.Ao invés disso,você chama um dos seguinte métodos,da classe controller:

  1. View – Retorna um action result ViewResult
  2. Redirect – Retorna um action result RedirectResult
  3. RedirectToAction – Retorna um action result RedirectToRouteResult
  4. RedirectToRoute – Retorna um action result RedirectToRouteResult
  5. Json – Retorna um action result JsonResult
  6. JavaScriptResult – Retorna um JavaScriptResult
  7. Content – Retorna um action result ContentResult
  8. File – Retorna um FileContentResult,FilePathResult,ou FileStreamResult dependendo dos parâmetros passados para o método

Então,se você quer retornar uma View para o navegador,você chama o método View().Se você quer redirecionar o usuario de uma action para outra,você chama o método RedirectToAction().Por exemplo,a action Details abaixo,ou mostra uma View ou redireciona o usuario para a action Index dependendo se o parâmetro ID tiver algum valor:

using System.Web.Mvc;

namespace MvcApplication1.Controllers
{
public class CustomerController : Controller
{
public ActionResult Details(int? id)
{
if (!id.HasValue)
return RedirectToAction(“Index”);

return View();
}

public ActionResult Index()
{
return View();
}

}
}

A ContentResult action é especial.Você pode usa-lo pra retornar um action result em formato de texto plano.Por exemplo,o método Index abaixo retorna o resultado como texto plano e não como HTML:

using System.Web.Mvc;

namespace MvcApplication1.Controllers
{
public class StatusController : Controller
{

public ActionResult Index()
{
return Content(“Hello World!”);
}

}
}

Quando o método Index é chamado uma View não é retornada.Ao invés disso,em seu lugar o texto plano “Hello World!” é retornado para o browser.

Se uma action retornar um valor que não seja um action result – por exemplo,uma Data ou um inteiro – então o resultado é colocado num ContentResult automaticamente.Por exemplo,quando o método Index abaixo é chamado, a data é colocada como ContentResult automaticamente:

using System;
using System.Web.Mvc; 

namespace MvcApplication1.Controllers
{
public class WorkController : Controller
{

public DateTime Index()
{
return DateTime.Now;
}

}
}

O ASP.NET MVC converte o objeto DateTime pra uma string e coloca o resultado num ContentResult automaticamente.O navegador recebe a data como texto plano.

É isso aí pessoal até apróxima!
Qualquer dúvida deixem comentários que responderei assim que possível.