Pergunta

Estou trabalhando em algumas leituras do ASP.NET MVC e tenho um aplicativo da web em funcionamento que migrarei de WebForms para MVC.Uma das solicitações de recurso que espero receber no processo é o retorno de uma visualização simplificada se o usuário estiver vindo de um dispositivo móvel.

Não consigo ver onde é o melhor lugar para implementar esse tipo de lógica.Tenho certeza de que há uma maneira melhor do que adicionar um if/else para Browser.IsMobileDevice em cada ação que retorna uma visualização.Que tipo de opções eu teria para fazer isso?

Foi útil?

Solução

Atualizar:Esta solução tem um bug sutil.A estrutura MVC chamará FindView/FindPartialView duas vezes:uma vez com useCache=true, e se isso não retornar um resultado, uma vez com useCache=false.Como há apenas um cache para todos os tipos de visualizações, os usuários móveis podem acabar vendo visualizações de desktop se um navegador de desktop for o primeiro a chegar.

Para aqueles interessados ​​em usar motores de visualização personalizados para resolver este problema, Scott Hanselman atualizou sua solução aqui:

http://www.hanselman.com/blog/ABetterASPNETMVCMobileDeviceCapabilitiesViewEngine.aspx

(Desculpas pelo sequestro da resposta, só não quero que mais ninguém passe por isso!)

Editado por roufamatic (17/11/2010)


A primeira coisa que você deseja fazer é apresentar o Arquivo do navegador de dispositivo móvel ao seu projeto.Usando este arquivo, você pode direcionar qualquer dispositivo ao qual deseja oferecer suporte, sem precisar saber os detalhes do que esses dispositivos enviam em seus cabeçalhos.Este arquivo já fez o trabalho para você.Em seguida, você usa a propriedade Request.Browser para personalizar a visualização que deseja retornar.

A seguir, crie uma estratégia sobre como você deseja organizar suas visualizações na pasta Visualizações.Prefiro deixar a versão desktop na raiz e depois ter uma pasta Mobile.Por exemplo, a pasta da visualização inicial ficaria assim:

  • Lar
    • Móvel
      • Iphone
        • Índice.aspx
      • Amora
        • Índice.aspx
    • Índice.aspx

Tenho que discordar do @Mehrdad sobre o uso de um mecanismo de visualização personalizado.O mecanismo de visualização serve a mais de um propósito e um desses propósitos é encontrar visualizações para o controlador.Você faz isso substituindo o método FindView.Neste método, você pode verificar onde encontrar a visualização.Depois de saber qual dispositivo está usando seu site, você pode usar a estratégia que criou para organizar suas visualizações para retornar a visualização desse dispositivo.

public class CustomViewEngine : WebFormViewEngine
{
    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
        // Logic for finding views in your project using your strategy for organizing your views under the Views folder.
        ViewEngineResult result = null;
        var request = controllerContext.HttpContext.Request;

        // iPhone Detection
        if (request.UserAgent.IndexOf("iPhone",
   StringComparison.OrdinalIgnoreCase) > 0)
        {
            result = base.FindView(controllerContext, "Mobile/iPhone/" + viewName, masterName, useCache);
        }

        // Blackberry Detection
        if (request.UserAgent.IndexOf("BlackBerry",
   StringComparison.OrdinalIgnoreCase) > 0)
        {
            result = base.FindView(controllerContext, "Mobile/BlackBerry/" + viewName, masterName, useCache);
        }

        // Default Mobile
        if (request.Browser.IsMobileDevice)
        {
            result = base.FindView(controllerContext, "Mobile/" + viewName, masterName, useCache);
        }

        // Desktop
        if (result == null || result.View == null)
        {
            result = base.FindView(controllerContext, viewName, masterName, useCache);
        }

        return result;
    }
}

O código acima permite definir a visualização com base em sua estratégia.A alternativa é a visualização da área de trabalho, se nenhuma visualização for encontrada para o dispositivo ou se não houver uma visualização móvel padrão.

Se você decidir colocar a lógica no seu controlador em vez de criar um mecanismo de visualização.A melhor abordagem seria criar um personalizado ActionFilterAttribute com os quais você pode decorar seu controlador.Em seguida, substitua o OnActionExecuted método para determinar qual dispositivo está visualizando seu site.Você pode verificar isso postagem no blog como fazer.A postagem também traz alguns links interessantes para alguns vídeos do Mix sobre esse assunto.

Outras dicas

No padrão do controlador de vista-visualização, é o controlador que escolhe a visão, então, não é tão ruim adicionar um if declaração e retorno uma visão apropriada. Você pode encapsular o if declaração em um método e chamá -lo:

return AdaptedView(Browser.IsMobileDevice, "MyView.aspx", model);

Como alternativa, você pode criar um mecanismo de exibição que execute dinamicamente uma visualização com base em ser móvel ou não. Não sou fã dessa abordagem, pois acredito que o controlador deve estar no comando. Por exemplo, se você estiver navegando no iPhone, pode querer ver a versão completa da área de trabalho. Na abordagem anterior, você passaria a bandeira booleana apropriada, mas neste último, as coisas se tornam mais complicadas.

Acho que o lugar certo para conectar essa funcionalidade é o ViewEngine personalizado.Mas você deve estar ciente de como IViewEngine.FindView método é chamado pelo ViewEngineCollection (saiba mais sobre isso aqui).

Atualizada solução sugerido por Scott Hanselman não funciona corretamente.Você pode encontrar meu exemplo de implementação desta abordagem aqui.Verifique o arquivo leia-me que descreve como você pode repetir o comportamento incorreto.

Sugiro outra abordagem que verifique se uma visualização não foi encontrada pelo ViewEngine original e se useCache parâmetro é true, verifica se a visualização existe no ViewEngine original com o parâmetro useCache=false.

É muito complexo colocar todo o código aqui, mas você pode encontrar a abordagem sugerida implementada em meu playground de código aberto aqui.Verificar MobileViewEngine testes de classe e unitários.

Alguns recursos do MobileViewEngine:

  • Funciona corretamente com o cache de visualização e usa o cache do mecanismo de visualização original.
  • Suporta ambos:nomes de visualizações de captura e caminhos de visualização relativos (~/Views/Index) usados ​​pelo modelo MvcContrib T4.
  • Resolve a visualização "Índice" da seguinte forma:
    • Mobile/Platform/Index – se a visualização existir e uma plataforma de dispositivo móvel (IPhone, Android etc.) estiver listada na lista de suporte.
    • Mobile/Index - visualizar todos os outros dispositivos móveis.Se a visualização não existir, você poderá, opcionalmente, retornar à versão de visualização para desktop.
    • Index – para versão desktop.
  • Você pode personalizar a hierarquia de visualização móvel (por exemplo, Mobile/ Platform/Manufacturer) ou personalize a resolução do caminho de visualização móvel adicionando/alterando regras de dispositivo (consulte MobileDeviceRule e PlatformSpecificRule).

Espero que isso ajude

Esta é uma versão que realmente funciona, tanto com o T4MVC quanto no modo de liberação (onde o cache de visualizações está ativado). Ele cuida dos UserControls e URLs absolutos/relativos também. Requer o Arquivo de navegador de dispositivos móveis.

public class MobileCapableWebFormViewEngine : WebFormViewEngine
{

    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
    {
        if (viewPath.EndsWith(".ascx"))
            masterPath = "";
        return base.CreateView(controllerContext, viewPath, masterPath);
    }
    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
        useCache = false;
        ViewEngineResult result = null;
        var request = controllerContext.HttpContext.Request;

        if (request.Browser.IsMobileDevice || request["mobile"] != null || request.Url.Host.StartsWith("m."))
        {
            var mobileViewName = GetMobileViewName(viewName);

            result = base.FindView(controllerContext, mobileViewName, masterName, useCache);
            if (result == null || result.View == null)
            {
                result = base.FindView(controllerContext, viewName, "Mobile", useCache);
            }
        }

        if (result == null || result.View == null)
        {
            result = base.FindView(controllerContext, viewName, masterName, useCache);
        }

        return result;
    }

    private static string GetMobileViewName(string partialViewName)
    {
        var i = partialViewName.LastIndexOf('/');
        return i > 0
                   ? partialViewName.Remove(i) + "/Mobile" + partialViewName.Substring(i)
                   : "Mobile/" + partialViewName;
    }
}

Sua lógica principal deve ser a mesma nos controladores e apenas a visualização necessária será alterada, para que o controlador seja onde você precisa da instrução IF/else para servir a visualização correta para cada ação do controlador, conforme declarado.

Uma alternativa seria envolver sua lógica controladora em uma DLL separada e depois ter controladores / caminhos diferentes para a versão móvel. Se um controlador regular receber uma solicitação de um dispositivo móvel, você poderá redirecioná -lo para sua área móvel, que contém todos os seus controladores móveis que usam a lógica do controlador compartilhado. Essa solução também permitiria que você fizesse 'toques' específicos para os controladores móveis e não o impactaram seus controladores regulares.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top