in ASP.NET

ASP.NET MVC Display Modes (construindo sites otimizados para mobile)

Com o crescimento de vendas e uso de smartphones, surge a necessidade (já antiga) de otimizar nossas aplicações e web sites para garantir a melhor experiência e entrega de nossos conteúdos, existem varias abordagens no desenvolvimento de web sites para esse objetivo, desde o carregamento de recursos sobre demanda, a modificação visual através de CSS e media queries, e outras diversas técnicas, como por exemplo a entrega de um site totalmente diferente em um subdomínio (m.exemplo.com.br).

Design Responsivo, Conteúdo Dinâmico ou Mobile Url?

O Google possui um material com recomendações para desenvolver um site que seja otimizado para ser acessado por diversos dispositivos móveis (https://developers.google.com/webmasters/smartphone-sites/details).

Nele existem três principais modelos:

  1. Web Design Responsivo, são sites que entregam o mesmo html pelas mesmas urls para os diversos dispositivos, ajustando a renderização da página com CSS para cada dispositivo.
  2. Conteúdo Dinâmico, consiste em servir diferentes conteúdos pela mesma url, entregando diferentes htmls e outros recursos da página, variando de acordo com o dispositivo que está acessando o site.
  3. Urls separadas para Mobile (m.exemplo.com.br), são aplicações com regras que identificam se um dispositivos é mobile, e redirecionam para um versão totalmente diferente da versão normal.

Desde as primeiras versões o ASP.NET oferece diversos modos de identificar o dispositivo que está acessando o site. Com o ASP.NET MVC 4 foi criada uma nova feature chamada Display Modes, que nos dá a possibilidade de selecionar e ter uma View apropriada para cada dispositivo ou navegador.

ASP.NET MVC Display Modes

O ASP.NET MVC Display Modes é uma feature que funciona fazendo a seleção apropriada da View para a requisição, levando em consideração o navegador que está fazendo a requisição. Por exemplo, se uma requisição de um desktop pela Home (default do projeto mvc), a aplicação irá procurar e escolher a view Views\Home\Index.cshtml, já em um requisição feita por um dispositivo mobile, primeiro a aplicação procurará a seguinte view: Views\Home\Index.mobile.cshtml, caso ela exista, a aplicação utilizará ela, caso esta view especifica para mobile não exista, a aplicação utilizará a view padrão (Views\Home\Index.cshtml).

Esta identificação é feita através de um header que os navegadores utilizam nas requisições, o header User-Agent (notem na requisição abaixo, em detalhe, o header).

image

 

Convention over configuration

O ASP.NET MVC busca sempre utilizar um conceito muito importante, a convenção sobre a configuração (Convention over configuration – CoC). No exemplo que comentei acima (acesso via mobile), a aplicação procurará primeiro a view apropriada NomeDaView.NomeDisplayMode.cshtml, caso não encontre ele utilizará a view NomeDaView.cshtml.

Por padrão temos dois Display Modes, um para a versão normal, e outro para a versão mobile.

ex: Index.cshtml (listando os Modes)

<div class="hero-unit">

    <h1>Display Modes</h1>
    <ul>
        @foreach (var item in DisplayModeProvider.Instance.Modes)
        {
            <li>DisplayMode: @item.DisplayModeId</li>
        }
    </ul>
</div>

 

Notem que é possível ver um modo com o nome vazio(“”) e outro com o nome “Mobile”.

image

 

Usando o Display Mode

Podemos usar o Display Mode em vários níveis da nossa aplicação, no exemplo abaixo eu criei uma versão da view Index.cshtml, nomeando ela como Index.Mobile.cshtml.

image

Index.cshtml

@{
    ViewBag.Title = "Home Page";
}

<div class="jumbotron">
    <h1>ASP.NET</h1>
    <p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
    <p><a href="http://asp.net" class="btn btn-primary btn-large">Learn more &raquo;</a></p>
</div>

<div class="row">
    <div class="col-md-4">
        <h2>Getting started</h2>
        <p>
            ASP.NET MVC gives you a powerful, patterns-based way to build dynamic websites that
            enables a clean separation of concerns and gives you full control over markup
            for enjoyable, agile development.
        </p>
        <p><a class="btn btn-default" href="http://go.microsoft.com/fwlink/?LinkId=301865">Learn more &raquo;</a></p>
    </div>
    <div class="col-md-4">
        <h2>Get more libraries</h2>
        <p>NuGet is a free Visual Studio extension that makes it easy to add, remove, and update libraries and tools in Visual Studio projects.</p>
        <p><a class="btn btn-default" href="http://go.microsoft.com/fwlink/?LinkId=301866">Learn more &raquo;</a></p>
    </div>
    <div class="col-md-4">
        <h2>Web Hosting</h2>
        <p>You can easily find a web hosting company that offers the right mix of features and price for your applications.</p>
        <p><a class="btn btn-default" href="http://go.microsoft.com/fwlink/?LinkId=301867">Learn more &raquo;</a></p>
    </div>
</div>

Index.Mobile.cshtml

@{
    ViewBag.Title = "Home Page";
}

<div class="jumbotron">
    <h1>ASP.NET - Versão Mobile</h1>
    <p class="lead">ASP.NET is a free web framework for building great Web sites and Web applications using HTML, CSS and JavaScript.</p>
    <p><a href="http://asp.net" class="btn btn-primary btn-large">Learn more &raquo;</a></p>
</div>

Quando acessamos a home do site em um Desktop, a view selecionada pela aplicação será a Index.cshtml.

image

Ao acessar a mesma url por um navegador mobile (no exemplo estou utilizando o Opera Mobile), podemos ver a view selecionada foi a Index.Mobile.cshtml.

image

Também é possível utilizar o mecanismo do Display Mode em Partials e em Layouts, no exemplo abaixo eu criei uma partial chamada _Menu.cshtml, e uma versão dela chama _Menu.Mobile.cshtml.

image

Esse menu será utilizado na pagina About, notem que eu passei como referencia somente o nome da partial (“Menu”), e o próprio mecanismo do Display Mode se encarrega de selecionar a versão mobile daquela partial, caso esta versão exista, e a requisição esta sendo feita por um dispositivo mobile.

image

Chrome e o Opera Mobile (Galaxy)

image

Além disso, também é possível utilizar esse mecanismo em versões para a Layout, no exemplo abaixo, eu criei uma versão _Layout.Mobile.cshtml, o que pode ser extremamente útil para o gerenciamento do carregamento de alguns scripts ou recursos.

image

 

Criando seu próprio Display Mode

O ASP.NET MVC é um framework extremamente customizável, no caso, o Display Mode nos permite criar nossos próprios “Modos” customizados, com base em alguma regra que podemos implementar, no exemplo abaixo, eu crio um Display Mode para iPhone, para isso precisarei adicionar um Display Mode, com a implementação de uma regra simples, que analisa o UserAgent da requisição.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using System.Web.WebPages;

namespace WebApplication10
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("iPhone")
            {
                ContextCondition = (context => context.Request.UserAgent.IndexOf
                    ("iPhone", StringComparison.OrdinalIgnoreCase) >= 0)
            });
        }
    }
}

A partir disso, já podemos criar uma view chamadas Index.iPhone.cshtml

image

E podemos ver o resultado na imagem abaixo (neste caso utilizei um recurso do Chrome para sobrescrever o User-Agent, “simulando” uma requisição vinda de um iPhone).

image

Override do Chrome (f12 para abrir a tool box)

image

View Switcher

O View Switcher é uma maneira que podemos disponibilizar para nossos usuário que querem acessar a versão Desktop em um dispositivo Mobile, com ele é possível sobrescrever a escolha da view de acordo com o navegador que está acessando nossos sites.

Para isso o ASP.NET disponibiliza alguns recursos para tratar a requisição, para isso vamos criar um Controller chamado ViewSwitcherController, e nele implementar o código que irá tratar o override da seleção das views de acordo com o navegador.

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

namespace WebApplication10.Controllers
{
    public class ViewSwitcherController : Controller
    {
        public RedirectResult SwitchView(bool mobile, string returnUrl)
        {
            if (Request.Browser.IsMobileDevice == mobile)
                HttpContext.ClearOverriddenBrowser();
            else
                HttpContext.SetOverriddenBrowser(mobile ? BrowserOverride.Mobile : BrowserOverride.Desktop);

            return Redirect(returnUrl);
        }
    }
}

Para acessar a action deste controller vou criar uma PartialView que será utilizada nas páginas que eu quero dar a opção do usuário acessar a versão original do site, mesmo estando em um dispositivo Mobile.

@if (Request.Browser.IsMobileDevice && Request.HttpMethod == "GET")
{
    <div>
        @if (ViewContext.HttpContext.GetOverriddenBrowser().IsMobileDevice)
        {
            @: Mobile view
            @Html.ActionLink("Desktop view", "SwitchView", "ViewSwitcher", new { mobile = false, returnUrl = Request.Url.PathAndQuery }, new { rel = "external" })
        }
        else
        {
            @:Desktop view
            @Html.ActionLink("Mobile view", "SwitchView", "ViewSwitcher", new { mobile = true, returnUrl = Request.Url.PathAndQuery }, new { rel = "external" })
        }
    </div>
}

Utilizei esta partial na Layout da minha aplicação.

image

Com isso, agora nossos usuários vindos de um dispositivo móvel terão a opção de acessar o site na versão original, e a opção de voltar para a versão mobile novamente.

Versão Mobile

image

Versão Desktop

image

Versão Desktop (notem a opção de voltar para a versão mobile)

image

Cookies

O mecanismo que o ASP.NET utiliza para entender esta opção do usuário é um Cookie chamado .ASPXBrowserOverride

image

Display Mode + OutputCache

Como o Display Mode utiliza o header User-Agent, e também, no caso do uso do View Switcher, ele também poderá utilizar um cookie para determinar qual a view correta para selecionar, é preciso ter em mente estas duas variação ao implementarmos o OutputCache em uma aplicação que utilizar o Display Mode.

Para isso, precisamos basicamente implementar a variação do OutputCache por estas variáveis, no exemplo abaixo, eu implemento a variação por header, e também implementei uma variação custom para analisar o cookie da requisição (no caso do uso do view switcher).

Global.asax

public override string GetVaryByCustomString(HttpContext context, string custom)
{
    if (custom == "CookieOverride")
        if (context.Request.Cookies[".ASPXBrowserOverride"] != null)
            return "1";

    return base.GetVaryByCustomString(context, custom);
}

HomeController.cs

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

namespace WebApplication10.Controllers
{
    public class HomeController : Controller
    {
        [OutputCache(Duration = 300, VaryByHeader = "User-Agent", VaryByCustom = "CookieOverride", Location = OutputCacheLocation.Server)]
        public ActionResult Index()
        {
            return View();
        }
    }
}

Bom espero que este post seja útil, estou a disposição para qualquer dúvida, crítica e sugestões.

Abs

Rodolfo

  • http://thiagocustodio.azurewebsites.net/ Thiago

    great post Rodolfo! Keep coding 😉

  • http://www.rodolfofadino.com.br/ Rodolfo Fadino

    Vlw mesmo 🙂

  • William Alves da Silva

    Muito bom Rodolfo eu poderia personalizar mais ainda e pegar a resolução do navegador e direcionar para diferentes views?