Elemar DEV

Tecnologia e desenvolvimento

Combinando uso de serviços (Web API) e páginas (MVC)

Olá pessoal. Tudo certo?!

Acredito que há uma tendência forte para que a “renderização” da interface com o usuário migre, cada vez mais, do servidor para o cliente. Vejo cada vez menos uso para o Razor (embora goste muito dele) e mais uso para Javascript+Knockout.

Um Model, dois Controllers

Considere o seguinte modelo:

namespace LearningAjaxOnMvc.Models
{
    public class Person
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string PictureUrl { get; set; }
        public string Bio { get; set; }
    }
}

Trata-se de uma entidade muito simples.

Em meu projeto Web, posso prover essa entidade de duas formas.

image Repare que para ter dois controllers com o “mesmo nome”, basta manter os dois em namespaces diferentes (dentro da pasta controllers).

Esta é a minha implementação para o Controller padrão:

using System.Web.Mvc;
using LearningAjaxOnMvc.Infrastructure;

namespace LearningAjaxOnMvc.Controllers
{
    public class PeopleController : Controller
    {
        readonly PeopleRepository repository = new PeopleRepository();
        public ActionResult Index()
        {
            return View(repository.GetAll());
        }

        public ActionResult Details(int id)
        {
            return View(repository.Get(id));
        }
    }
}

Esta é a minha implementação para o Controller da API.

using System.Net;
using System.Web.Http;

using LearningAjaxOnMvc.Models;
using LearningAjaxOnMvc.Infrastructure;

namespace LearningAjaxOnMvc.Controllers.Api
{
    public class PeopleController : ApiController
    {
        readonly PeopleRepository repository = new PeopleRepository();
        
        public Person Get(int id)
        {
            var result = repository.Get(id);
            if (result == null)
                throw new HttpResponseException(HttpStatusCode.NotFound);
            return result;
        }
    }
}

Um dos controllers provê uma interface padrão, HTML. O outro pode prover dados de uma instância, como serviço.

Consumindo o serviço em Client-side

Vamos assumir agora o seguinte Razor para a action Index:

@model System.Linq.IQueryable<LearningAjaxOnMvc.Models.Person>
@{
    ViewBag.Title = "People";
}
<h2>People</h2>

<ul class="people">
    @foreach (var person in Model)
    {
        <li>@Html.ActionLink(@person.FirstName, "Details", new { id = @person.Id }) </li> 
    }
</ul>

Como você pode ver, este bloco ignora completamente o serviço. Afinal, todos os links apenas apontam para outras Actions. Entretanto, a coisa muda um pouco se adicionarmos o seguinte script:

$(function() {
    $("ul.people a").click(function (event) {
        event.preventDefault();
        var original = $(this).attr("href");
        var url = "/api" + original.replace("/Details", "");
        $.getJSON(url, null, function (person) {
            alert(person.Bio);
        });
    });
});

Esse trecho de código, deliberadamente, altera o comportamento dos links fazendo com que eles passem a acessar o serviço para obter dados. Veja:

image

Alterando a estrutura do documento com KnockoutJS

O acesso a serviços dá mais liberdade para que a interface seja trabalhada “client-side”. Podemos usar, por exemplo, knockout. Considere o seguinte template:

<div data-bind="visible: showData">
    <img data-bind="attr: { src: pictureUrl }"/>
    <h2 data-bind="text: fullName"></h2>
    <p data-bind="text: bio" />
</div>

Esse modelo é “alimentado” pelo seguinte ViewModel. Veja:

var ViewModel = function () {
    this.showData = ko.observable(false);

    this.firstName = ko.observable("");
    this.lastName = ko.observable("");

    this.fullName = ko.computed(function () {
        return this.lastName() + ", " + this.firstName();
    }, this);

    this.bio = ko.observable("");
    this.pictureUrl = ko.observable("");
};

var instance = new ViewModel();
ko.applyBindings(instance);

Que é atualizado pela seguinte consulta ao serviço:

$("ul.people a").click(function (event) {
    event.preventDefault();
    var original = $(this).attr("href");
    var url = "/api" + original.replace("/Details", "");
    $.getJSON(url, null, function (person) {
        instance.showData(true);
        instance.firstName(person.FirstName);
        instance.lastName(person.LastName);
        instance.bio(person.Bio);
        instance.pictureUrl(person.PictureUrl);
    });
});

Resultado:

image

Não sou designer, nem pensei em deixar esse conteúdo bonito. Entreanto, veja como nosso “Detail” foi todo montado no cliente.

Era isso.

17 comentários em “Combinando uso de serviços (Web API) e páginas (MVC)

  1. “Acredito que há uma tendência forte para que a “renderização” da interface com o usuário migre, cada vez mais, do servidor para o cliente”

    O que o twitter está fazendo é o contrario, saindo da renderização client para renderização servidor, segue o link da informação do proprio twitter => http://engineering.twitter.com/2012/05/improving-performance-on-twittercom.html

    Como você mesmo disse, sempre depende, e creio que podemos ter algo bacana misturando os dois, com uso do knockout!

    • elemarjr
      31/05/2012

      Muito obrigado pela referência. Excelente!

      No post deles, eles comentam (entre outras coisas) sobre o “problema” da diferença de performance dos browsers e máquinas no cliente. Logo, percebiam uma disparidade nos tempos de renderizar as páginas. É um aspecto importante.

      Na minha interpretação, este foi o único problema “de fato”, com a renderização client-side. No mais, foram “falhas” (se é que esse termo se aplica em uma arquitetura tão densa como a do twitter) de design, implicando em: nro. grande de requests de recursos, download de recursos desnecessários, etc…

      O que acha?

      • No projeto atual na empresa tínhamos uma arquitetura client-side parecida com a do twitter, e sempre que o user entrava de uma pagina X ele sempre tinha que passar pelo começo, o mesmo que acontece com o twitter, gerando trafego desnecessário, hoje mudamos e temos um modo hibrido, temos renderização server-side, mas precisamos de dinamicidade no client-side, e usamos knockout para isso.
        Em relação ao tempo de renderização client-side não creio que o cliente seja o vilão, mas sim como eles fizeram, usaram alguns plugins pouco performáticos.
        O maior trafego do twitter hoje é mobile, e temos aplicações rápidas, que carregam os tweets em pouco tempo, diferente do facebook, que esse é mais rápido na UI do browser que o twitter.
        Acho que foi um pouco redundante, mas hoje gosto de uma arquitetura hibrida, mas como depende do cenário, temos que avaliar!

  2. elemarjr
    31/05/2012

    Echo de uma resposta minha, sobre esse mesmo tópico, no DNA (https://groups.google.com/forum/?fromgroups#!topic/dotnetarchitects/0txfpDCL8nA).

    Alguns “pensamentos soltos”:

    * Experiência do usuário é algo fundamental e, ao meu ver, antecede questões de “praticidade” no desenvolvimento de aplicações (claro, sempre há o “depende”)

    * Com HTML5 (e tecnologias afins), resolvemos o problema do cliente desconectado. O “mundo do negócio” espera ter continuidade de uso mesmo sem conexão (tipo, em uma viagem de avião). Por isso, estão surgindo estratégias de “rodar off”. Rodando off, renderização (ou boa parte dela) é client-side.

    * Para mim, a tendência de renderizar conteúdo client-side está vindo “de carona” (mais rápido) com a necessidade da entrega de APIs mais ricas. Vejam: com o surgimento das Apps, muitos sites, inclusive do Twitter, perderam muito de sua relevância. Estamos no meio de uma revolução em que nossas soluções estão sendo “empurradas” para uma multiplicidade real de plataformas.

    * Uma questão cada vez mais relevante diz respeito a capacidade computacional dos clientes. Cada vez menos sabemos o “canhão” que está sendo usado do outro lado. Essa resposta, por exemplo, está sendo escrita em um iPad 1 (que não é nenhuma super-máquina). Também há a questão da banda, que oscila bastante.

    * Interfaces fluídas precisam de planejamento. Cansei de ter “botões” mudando de lugar em UIs mal-planejadas.

  3. Brandão
    31/05/2012

    Tenho que dizer que gosto mais desse modo de desenvolver Web que todos os outros.
    Acho bem menos confuso, tanto o Web Forms como MVC me pareciam “misturados”.

    • Gostaria de saber por que!

      • egomesbrandao
        31/05/2012

        Por que no Web Forms e MVC existe uma mistura de HTML com as “server side” tags, apesar de no MVC com Razor a leitura do código ficar melhor, com Web API, mais o uso dos frameworks JS separa-se melhor ainda o código.

        • Sempre foi possível fazer isso com Web Forms e MVC, no web forms bastava eu ter um IHttpHandler que cuspia json no corpo do http, da mesma forma o mvc, que ja tinha facilidades para isso, inclusive tendo frameworks como restfulie para fazer negociação de conteúdo(coisa que é nativa no Web API).

  4. Ainda não usei Knockout, mas estou curtindo o que estou lendo e vendo por aí… Bom demais esse post, Elemar!
    Não sei se essa é a mesma visão de vocês, mas a impressão que tenho é que com a chegada do MVC o javascript voltou a ser MUITO mais utilizado do que antes e mais “frameworks” js estão sendo criados. Acho fantástico tudo isso e concordo com a frase do Elemar: “Estamos no meio de uma revolução em que nossas soluções estão sendo “empurradas” para uma multiplicidade real de plataformas.”

    • Knockout é um bom framework para isso, mas temos outros como Backbone.js, e uma infinidade de plugins de templates, dentre eles mustache que era o que o twitter usava.
      Gosto do ko por que foco na regra e não na manipulação do DOM, isso ele faz para mim!

  5. tucaz
    31/05/2012

    Gosto muito da idéia de renderizar a UI inteira (ou boa parte) no cliente. No entanto, vejo dois grandes pontos que seguram a adoção:

    - A maioria dos desenvolvedores ainda luta pra escrever código server side de boa qualidade utilizando linguagens OO. Só agora estamos aprendendo a fazer isso de uma maneira mais organizada, performática e funcional. Colocar toda essa lógica, que geralmente está no server, no cliente implica em escrever bom código javascript quando a maioria dos desenvolvedores ve javascript apenas como function ValidarCamposFormulario(). Eu mesmo, venho me dedicando já há algum tempo ao estudo de javascript, mas ainda sinto que tenho muito a percorrer. Em resumo, devido ao histórico de uso de javascript somente pra validação de formulários e coisas similares quando um desenvolvedor, mesmo experiente em linguagens server side, ve uma “classe” ou métodos mais elaborados rola um blue screen of death.

    - Dada a larga adoção de javascript nos últimos tempos, muito código foi escrito e muitos componentes e frameworks criados. Alguns passaram por um buzz e tem alto uso mesmo sem estar preparados pra isso. Nestes casos, temos código javascript que gera muito footprint deixando todo o processo no cliente lento. Como é muito fácil misturar plugins e códigos encontrados na web o resultado disso geralmente compromete muito a performance das aplicações, já que a qualidade é duvidosa. São poucas aplicações utilizando esta técnica que funcionam bem, realmente.

  6. Para quem ja teve a curiosidade de ver o VS 2012, sinto dizer que removeram o template de SPA.

    http://blogs.msdn.com/b/webdevtools/archive/2012/05/31/new-features-for-web-development-in-visual-studio-2012-rc.aspx?CommentPosted=true#commentmessage

    “Cleaned up Empty template (now it’s really empty), added basic template, removed “Single Page Application” for MVC4.”

    Eu gostava muito disso, por que será que fizeram isso?

  7. Junior
    02/06/2012

    Mais um ótimo post Elemar. Eu também venho notando essa tendência e já acendi a luz amarela. Acho que Javascript + Knockout um ótimo pontapé inicial pra quem quiser se aventurar nessa nova arquitetura.

  8. Desenvolvendo Fé
    23/07/2012

    Gostei muito da utilização Javascript+Knockout. Mas o que pensam sobre renderização no lado servidor utilizando partial views? Carregar o necessário via GET.

Deixe um comentário

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

Informação

Publicado às 30/05/2012 por em Post e marcado , , , , .

Estatísticas

  • 626,615 hits
%d blogueiros gostam disto: