Domanda

Sto lavorando la mia strada attraverso qualche lettura ASP.NET MVC e ho una web app sul posto di lavoro che sarò la migrazione da WebForms a MVC. Una delle richieste di funzionalità mi aspetto di ottenere nel processo è di avere una vista semplificata restituita se l'utente proviene da un dispositivo mobile.

Non riesco a vedere dove il posto migliore è quello di attuare quel tipo di logica. Sono sicuro che c'è un modo migliore di aggiungere un if / else per Browser.IsMobileDevice in ogni azione che restituisce una visione. Che tipo di opzioni avrei dovuto fare questo?

È stato utile?

Soluzione

Aggiorna : questa soluzione ha un bug sottile. Il framework MVC chiamerà in FindView / FindPartialView due volte: una volta con useCache=true, e se questo non restituisce un risultato, una volta con useCache=false. Dal momento che c'è una sola cache per tutti i tipi di viste, gli utenti mobili possono finire per vedere viste sul desktop quando un browser desktop è stato il primo ad arrivare.

Per chi fosse interessato ad utilizzare i motori di visualizzazione personalizzata per risolvere questo problema, Scott Hanselman ha aggiornato la sua soluzione qui:

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

(Ci scusiamo per la risposta dirottamento, io non voglio nessun altro di dover passare attraverso questo!)

A cura di roufamatic (2010-11-17)


La prima cosa che voglio fare è introdurre il Mobile Device Browser File al progetto. Utilizzando questo file è possibile target che cosa mai dispositivo che si desidera supportare, senza dover conoscere le specifiche di ciò che questi dispositivi inviano nelle intestazioni. Questo file ha già fatto il lavoro per voi. È quindi utilizzare la proprietà Request.Browser sarto che vista che si desidera tornare.

Avanti, venire con una strategia su come si desidera organizzare le vostre opinioni nella cartella Visualizzazioni. Preferisco lasciare la versione desktop alla radice e quindi avere una cartella Mobile. Ad esempio, la cartella di vista iniziale sarebbe simile a questa:

  • Inizio
    • mobile
      • iPhone
        • Index.aspx
      • BlackBerry
        • Index.aspx
    • Index.aspx

Non sono d'accordo con @Mehrdad sull'utilizzo di un motore di visualizzazione personalizzata. Il motore di visualizzazione serve più di uno scopo e uno di questi obiettivi è trovare una vista per il controller. A tale scopo, l'override del metodo FindView. In questo metodo, si può fare i vostri controlli su dove trovare la vista. Dopo aver individuato quale dispositivo sta utilizzando il vostro sito, è possibile utilizzare la strategia si avvicinò con per organizzare le vostre opinioni per tornare la vista per quel 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;
    }
}

Il codice di cui sopra consente di impostare la visualizzazione in base alla tua strategia. La parte posteriore caduta è la vista del desktop, se senza vista è stato trovato per il dispositivo o se non c'è una vista cellulare di default.

Se si decide di mettere la logica nel controller di invece di creare un motore di visualizzazione. L'approccio migliore sarebbe quello di creare un costume ActionFilterAttribute che potete decorare il controller di con. Poi sovrascrivere il OnActionExecuted metodo per determinare quale dispositivo sta visualizzando il tuo sito. È possibile controllare questo post sul blog fuori su come. Il post ha anche alcune belle link ad alcuni video Mix proprio su questo argomento.

Altri suggerimenti

Nel pattern Model-View-Controller, è il controller che sceglie vista, quindi, non è poi così male per aggiungere una dichiarazione if e restituire una vista appropriata. È possibile incapsulare la dichiarazione if in un metodo e chiamare:

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

In alternativa, è possibile creare un motore di visualizzazione che esegue dinamicamente una vista basata su che si tratti di mobili o no. Io non sono un fan di questo approccio, poiché credo che il regolatore dovrebbe essere in carica. Per esempio, se si sta navigando su iPhone, si potrebbe desiderare di vedere la versione completa desktop invece. Nel primo approccio, che ci si passa il flag booleano appropriata, ma in quest'ultimo, le cose diventano più complicate.

Credo che il posto giusto per inserire questa funzionalità è ViewEngine personalizzato. Ma si deve essere consapevoli di come metodo IViewEngine.FindView viene chiamato dal ViewEngineCollection (per saperne di più su questo qui ).

suggerito da Scott Hanselman non funziona correttamente. È possibile trovare il mio esempio di implementazione di questo approccio qui . Verificare file readme che descrive come è possibile ripetere un comportamento scorretto.

Suggerisco un altro approccio che controlla se la vista non è stato trovato da ViewEngine originale e se il parametro è useCache true, controlla se esiste in vista ViewEngine originale con il parametro useCache=false.

E 'troppo complesso per mettere tutto il codice qui, ma è possibile trovare l'approccio suggerito implementato nel mio parco giochi open-source qui . Controllare classe MobileViewEngine e unità di test.

Alcune caratteristiche MobileViewEngine:

  • funziona correttamente con vista caching e utilizza la cache view motore originale.
  • Supporta entrambe: i nomi shot Vista e percorsi di vista relativi (~ / Vista / index) utilizzati dai template T4 MvcContrib
  • .
  • Risolve "Indice" Vedi come segue:
    • Mobile/Platform/Index -. Se vista esiste e una piattaforma per dispositivi mobili (iPhone, Android, ecc) viene arruolato nella lista supportati
    • Mobile/Index - vista per tutti gli altri dispositivi mobili. Se la vista non esiste si può opzionalmente fallback alla versione visualizzazione desktop.
    • Index - per la versione visualizzazione desktop.
  • È possibile personalizzare la gerarchia vista mobile (ad esempio Mobile/ Platform/Manufacturer) o personalizzare cellulare risoluzione percorso vista aggiungendo / cambiando le regole dei dispositivi (vedi MobileDeviceRule e PlatformSpecificRule).

La speranza, ciò contribuirà a

Questa è una versione che funziona in realtà, entrambi con T4MVC e nella modalità di rilascio (in cui è abilitata la memorizzazione nella cache di punti di vista). Non prendersi cura di usercontrols e relativi URL / assoluti pure. Richiede l' Mobile Browser Device File .

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;
    }
}

La logica di base dovrebbe essere lo stesso nei controllori e solo la vista è necessario cambierà in modo che il controller è dove l'avete bisogno l'istruzione if / else per servire la vista corretto per ogni azione di controllo come avete dichiarato.

Un'alternativa sarebbe quella di avvolgere voi Logic Controller in una DLL separata e quindi avere diversi controllori / percorsi per la versione mobile. Se un controller normale riceve una richiesta da un dispositivo mobile si possono reindirizzare alla vostra zona cellulare che contiene tutti i controller di mobili che utilizzano la logica di controllo condiviso. Questa soluzione consentirebbe anche di fare 'tweeks' che sono specifici per i controllori di telefonia mobile e non l'hanno impatto i controller regolari.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top