Comparativo: MVC vs. WebForms


Recentemente a Microsoft disponibilizou a implementação do padrão MVC. Esta versão encontra-se em CTP e está disponível para ser baixada neste link. A idéia deste post é mostrar uma comparação saudável e técnica do modelo tradicional do ASP.NET (WebForms) em comparação com o  MVC.

Introdução

Desde o lançamento da plataforma .NET até a versão mais recente – 3.5 – o ASP.NET é baseado em um modelo chamado de WebForms que, desde então, foi uma das grandes mudanças, talvez uma das mais impactantes, que a Microsoft fez em sua estrutura de desenvolvimento para aplicações Web. O ASP classico deixou de ser utilizado, devido a estrutura estável, performática, reutilizável e simples que é o ASP.NET.

Por sua vez, o ASP.NET possui uma série de características que o tornam simples de utilizar, mas não menos robusto. A quantidade de controles ricos que o mesmo fornece é extremamente grande, onde precisaríamos de uma série de linhas de código HTML + CSS para ter um resultado igual. Mesmo com essa facilidade e toda sua extensibilidade (como é caso dos Control Adapters), muitos desenvolvedores sentem a necessidade de ter um maior controle sobre como o conteúdo está sendo renderizado para o cliente e como os dados que o cliente informa são enviados para a aplicação.

Devido a estrutura do ASP.NET e seus controles intrínsicos, a renderização final acaba sendo delegada ao runtime do ASP.NET e é neste momento que desenvolvedores sentem a necessidade de uma maior flexibilidade. O padrão MVC (Model-View-Controller) garante isso. Este padrão não nasceu agora. Já existem vários Frameworks que você pode acoplar ao ASP.NET e desenvolver aplicações baseadas neste modelo. O que vemos neste momento é uma implementação deste padrão pela própria Microsoft, integrando fortemente à infraestrutura do ASP.NET.

Arquitetura

O ASP.NET WebForms é baseado em um padrão chamado Page Controller.  Já o modelo MVC baseia-se em um outro padrão, chamado de Front Controller. Cada um desses padrões tem suas vantagens e desvantagens que podem ser analisadas e comparadas através do link definido acima.

Além dos padrões, o modelo WebForms possui algumas características muito interessantes, que tornaram o ASP.NET muito fácil de desenvolver, acabando com aquele abismo que existia entre programadores Windows e Web. Para que isso fosse possível, funcionalidades como o ViewState, CodeBehind, Server Controls foram essenciais, mas que, no mundo MVC, acabam não sendo utilizados.

Páginas vs. Ações

Quando uma requisição chega para uma aplicação ASP.NET baseada no modelo tradicional, a página requisitada é mapeada para uma página (*.aspx). Esta página contém código HTML que representa a visualização da mesma e que será processada pelo ASP.NET e, em seguida, gerado um output e enviado ao usuário que a requisitou.

No modelo MVC, isso mudará drasticamente. Ao invés de você fazer requisição para uma página, você requisitará uma ação. Esta ação nada mais é do que um método que estará dentro de um determinado Controller. O Controller é responsável por capturar as informações fornecidas pelo protocolo HTTP ou pelo usuário, manipular essas informações, acessar o Model e, finalmente, renderizar o conteúdo, através de uma View, para o usuário.

Runtime

Quando uma requisição chega para uma aplicação ASP.NET tradicional, o runtime primeiramente executará vários de passos até que a página ASPX seja efetivamente executada. Muitos deles serão omitidos neste post ou serão comentados superficialmente (para maiores detalhes, consulte este artigo). Durante os passos que são omitidos nestes posts, estão a construção do AppDomain e a criação de objetos extremamente importantes para a execução da mesma, como o HttpContext, HttpApplication, etc. Depois que estes objetos estão devidamente criados, em algum momento, o ASP.NET determina qual será o handler responsável por executar a página; assim que este handler é determinado, o método ProcessRequest da página é executado e o ciclo de vida da mesma inicia, executando os métodos que criam os controles na página (baseando-se no HTML), os eventos da própria página, como Init, Load, etc., e eventos de controles que, possivelmente, podem acontecer.

No modelo MVC esse comportamento é radicalmente diferente. O motivo é porque as requisições para aplicações MVC são feitas para ações e não para páginas. Devido a isso, um módulo chamado UrlRoutingModule é adicionado a esta aplicação que intercepta a requisição no evento PostResolveRequestCache e PostMapRequestHandler. Este módulo é responsável por efetuar o parser da requisição e encontrar uma rota que se encaixa com a requisição. O mapeamento das requisições para o Controller/Ação é realizado no arquivo Global.asax e será tema de um futuro post/artigo.
 
Depois disso, um handler chamado MvcHandler é disparado. Ele é responsável por encontrar e instanciar o Controller correspondente e executar a respectiva ação requisitada pelo usuário. A idéia dentro desta ação é acessar o Model para extrair informações, definir possíveis regras de exibição e renderizar a visualização através do método RenderView. Este método recebe como parâmetro uma string, que representa a página a ser exibida; a responsabilidade deste método é justamente encontrar tal página ASPX e executá-la.

Todos os Controllers das aplicações herdam direta ou indiretamente da classe Controller que fornece toda essa infraestrutra. Não diferente, as páginas que servem como View, devem herdar da classe ViewPage ou ViewPage<TViewData>. Apesar de ser um Framework ainda bem novo, já existe a possibilidade de você customizar alguns funcionalidades, como a criação do Controller (ControllerBuilder) e também da geração da View (ViewFactory) e que podem ser facilmente plugáveis à infraestrutura do MVC, mas isso exige um post/artigo mais detalhado.

Segurança

Funcionalidades como o Membership e Roles continuam sendo suportadas normalmente, com apenas um detalhe com relação a restrição de páginas por grupos/usuários. Até então, quando queremos barrar o acesso a um determinado grupo/usuário à uma página, especificamos isso no Web.Config da aplicação, como pode ser visto através do trecho de código abaixo:

<location path=”Contas/ContaCorrente.aspx”>
  <system.web>
    <authorization>
      <allow roles=”Gerentes” />
      <deny users=”*” />
    </authorization>
  </system.web>
</location>

No modelo MVC isso não funcionará. Como falamos acima, o modelo MVC se baseia na execução de ações e não em páginas. Isso quer dizer que você terá que, ao invés de especificar a página, informar a ação e qual grupo/usuário poderá acessá-la. No modelo MVC deveríamos ter algo mais ou menos como:

<location path=”Contas/ExibirContaCorrente”>
  <system.web>
    <authorization>
      <allow roles=”Gerentes” />
      <deny users=”*” />
    </authorization>
  </system.web>
</location>

[ControllerAction]
public void ExibirContaCorrente()
{
     //regras
     RenderView(“ContaCorrente”);  //ContaCorrente.aspx
}

Em alternativa a isso, podemos recorrer a programação declarativa e utilizar atributos para especificar a autorização. Com a segurança declarativa, podemos decorar o método de ação com o atributo PrincipalPermissionAttribute e especificar o(s) grupo(s) que poderão ter acesso ao respectivo método. Fredrik Normén explica maiores detalhes desta implementação neste post.

Um outro exemplo é com relação a página de autenticação (Login) da aplicação. Ela também será uma ação de algum Controller que deverá ser executada quando o usuário desejar efetuar o login. Com isso, o atributo loginUrl do elemento <forms /> não apontará mais para uma página, mas sim para uma ação que se encarregará de exibir a página de autenticação para o usuário. Troy Goode mostra como aplicar essa técnica através deste post.

Testes

A partir do momento que você vê os testes como algo benéfico para o bom funcionamento das aplicações, você irá querer implementar isso em qualquer tipo de aplicação, mesmo em aplicações ASP.NET. Infelizmente, aplicações ASP.NET desenvolvidas em sua estrutura tradicional (WebForms), tornam a realização dos testes extremamente difícil, já que uma única classe/página é responsável por tratar da exibição dos dados, exibir os dados e capturar as informações fornecidas pelo usuário e enviar para a aplicação novamente. Esse modelo nos obrigará a instanciar essa classe e, para isso, será necessário que a mesma esteja sendo executada dentro do IIS, criando um forte acoplamento.

Isso já será bem mais flexível no modelo MVC, pois as três partes são independentes/desacopladas, permitindo que os testes sejam realizados de forma isolada ao resto do Framework. Somente um detalhe importante aqui é com relação a utilização de recursos específicos do protocolo HTTP (como QueryStrings, Forms, Headers, etc.); ao utilizar isso dentro da classe Controller você amarra isso ao ASP.NET e, segundo Phil Haack, eles estarão disponibilizando Interfaces que poderemos efetuar o mock destes objetos.

Server Controls (runat=”server”)

Acredito que aqueles que recorrem ao uso do modelo MVC provavelmente querem também ter o controle da criação dos controles e dificilmente deverão utilizar os controles fornecidos pelo ASP.NET.

Mesmo assim, felizmente a Microsoft se preocupou com a gama de controles que ela disponibiliza na ToolBox do Visual Studio .NET, e permite que utilizamos tais controles em aplicações que utilizam o modelo MVC, mas com algumas limitações:

• A forma que você popula os controles muda ligeiramente para se adequar a este modelo, mas ganhamos a facilidade do drag-and-drop e a geração automática do respectivo HTML. E além de tudo isso, a Microsoft garante que os Server Controls continuarão evoluindo com as futuras versões da plataforma e, conseqüentemente, suportados em ambos modelos.

• Apesar dos Server Controls serem suportados, o MVC não utiliza o conceito de Postback para se comunicar com o servidor, justamente porque tudo será baseado em ações, e o mesmo deverá ser redirecionado para uma ação específica dentro de algum Controller.

Outras Funcionalidades

Algumas funcionalidades do ASP.NET provavelmente perderão o sentido dentro deste modelo, como é o caso dos Control Adapters (já mencionado acima). Outras funcionalidades, que já utilizamos tradicionalmente, continuam sendo suportadas dentro deste modelo, como por exemplo ASCX, Master Pages, Session State, Caching, Url Authorization, etc..

Outras funcionalidades ainda não se sabe se serão suportadas dentro deste modelo, como é o caso das páginas assíncronas. Com este modelo, quem executa a parte “pesada” é o Controller e não mais a página. Sendo assim, não temos que fazer a página executar assincronamente já que, neste momento, o processo custoso já foi realizado. Imaginei que a Microsoft pudesse fazer algo como:

[ControllerAction]
[ExecuteInBackground]
public void CalcularPorcentagemDeComissao(int? gerenteId)
{
     //processo custoso
     RenderView(“Resultado”, null);
}

… e assim o processo seria executado em uma worker thread ao invés de utilizar uma thread retirada do ThreadPool que poderia servir páginas mais simples/leves.

Futuro

Este post foi baseado na versão CTP do ASP.NET MVC Framework. Provavelmente este Framework evoluirá bastante até sua versão final. Acredito que em breve, a Microsoft lançará uma nova versão, com possíveis melhorias no que diz respeito a execução e renderização dos controles. Até lá, muitas informações serão disponibilizadas pela comunidade, como é o caso do MVC Toolkit.

Para aqueles que pretendem estudar mais sobre este Framework, aconselho que assinem os blogs do Scott Guthrie, Fredrik Normém, Phil Haack, Rob Conery, Scott Hanselman e Luis Abreu que, sob-demanda, publicarão informações importantes sobre o assunto e o blog do Eduardo Miranda, que fala muito sobre testes.

Conclusão

Particularmente, gosto bastante do modelo WebForms e, até o presente momento, sempre consegui extrair bons resultados deste modelo. Vejo o MVC como uma alternativa bastante interessante ao modelo tradicional e que acredito que será bem aceito pela comunidade. Mesmo que o código C# ou VB.NET que consta no arquivo ASPX é referente a renderização, não gosto muito desta mistura (um pouco confuso?), e acho que isso é talvez por estar habituado ao code-behind. O Framework vai evoluir muito e, acredito que em pouco tempo, teremos várias novidades e, conseqüentemente, poderemos tirar maiores conclusões a respeito destes dois modelos.

Anúncios

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s