2009-09-07 16 views
27

Ich arbeite meinen Weg durch einige ASP.NET MVC lesen und ich habe eine Web-App bei der Arbeit, die ich von WebForms zu MVC migrieren werde. Eine der Featureanforderungen, die ich in diesem Prozess erwarten werde, ist eine vereinfachte Ansicht, wenn der Benutzer von einem mobilen Gerät kommt.Wie würde ich ASP.NET MVC-Ansichten basierend auf dem Gerätetyp ändern?

Ich kann nicht ganz sehen, wo der beste Ort ist, um diese Art von Logik zu implementieren. Ich bin mir sicher, dass es einen besseren Weg gibt, als ein if/else für Browser.IsMobileDevice in jeder Aktion hinzuzufügen, die eine Ansicht zurückgibt. Welche Art von Optionen würde ich tun müssen?

Antwort

21

Aktualisieren: Diese Lösung hat einen kleinen Fehler. Das MVC-Framework wird zweimal in FindView/FindPartialView aufrufen: einmal mit useCache=true, und wenn das kein Ergebnis zurückgibt, einmal mit useCache=false. Da für alle Arten von Sichten nur ein Cache verfügbar ist, sehen mobile Benutzer möglicherweise Desktop-Ansichten, wenn ein Desktop-Browser als erster eintrifft.

diejenigen Interessierten in benutzerdefinierte Ansicht Engines, dieses Problem zu lösen, hat Scott Hanselman seine Lösung hier aktualisiert:

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

(Apologies für die Antwort Hijack, ich jemand will nicht nur anderes haben durch diese gehen!)

Herausgegeben von roufamatic (2010-11-17)


Das erste, was Sie tun möchten, ist die Einführung des Mobile Device Browser File zu Ihrem Projekt. Mit dieser Datei können Sie gezielt auf jedes Gerät zugreifen, das Sie unterstützen möchten, ohne die Einzelheiten dessen kennen zu müssen, was diese Geräte in ihren Headern senden. Diese Datei hat die Arbeit für Sie bereits erledigt. Anschließend verwenden Sie die Request.Browser-Eigenschaft, um die Ansicht anzupassen, die Sie zurückgeben möchten.

Als nächstes finden Sie eine Strategie, wie Sie Ihre Ansichten unter dem Ordner Ansichten organisieren möchten.Ich ziehe es vor, die Desktop-Version im root zu lassen und dann einen Mobile-Ordner zu haben. Zum Beispiel würde die Home-Ansicht Ordner wie folgt aussehen:

  • Startseite
    • Mobil
      • iPhone
        • Index.aspx
      • Blackberry
        • Index.aspx
    • Index.aspx

Ich habe mit @Mehrdad anderer Meinung zu sein über eine benutzerdefinierte Ansicht-Engine. Die View-Engine dient mehr als einem Zweck, und einer dieser Zwecke besteht darin, Ansichten für den Controller zu finden. Sie tun dies, indem Sie die FindView-Methode überschreiben. In dieser Methode können Sie überprüfen, wo die Ansicht zu finden ist. Nachdem Sie wissen, welches Gerät Ihre Site verwendet, können Sie die Strategie, die Sie zum Organisieren Ihrer Ansichten entwickelt haben, verwenden, um die Ansicht für dieses Gerät zurückzugeben.

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

Mit dem obigen Code können Sie die Ansicht basierend auf Ihrer Strategie festlegen. Der Rückfall ist die Desktop-Ansicht, wenn keine Ansicht für das Gerät gefunden wurde oder wenn keine Standard-Ansicht für Mobilgeräte vorhanden ist.

Wenn Sie sich dafür entscheiden, die Logik in Ihren Controller zu legen, anstatt eine View-Engine zu erstellen. Der beste Ansatz wäre, eine benutzerdefinierte ActionFilterAttribute zu erstellen, mit der Sie Ihren Controller dekorieren können. Überschreiben Sie dann die OnActionExecuted-Methode, um festzustellen, welches Gerät Ihre Site anzeigt. Sie können dies überprüfen blog post auf, wie man. Der Beitrag enthält auch einige nette Links zu einigen Mix-Videos zu diesem Thema.

+0

helfen Wird nicht mit T4MVC arbeiten, übernehmen Sie die Viewname ist nur ein Name und kein Pfad. funktioniert auch nicht im Freigabemodus wegen der Zwischenspeicherung. –

+0

Habe es nicht versucht seit T4MVC veröffentlicht wurde. Das war vorher, das war verfügbar. Wenn ich Zeit habe, werde ich die Antwort aktualisieren, um meine Ergebnisse beim Testen gegen T4MVC widerzuspiegeln. –

+0

Carl, was meinst du mit Caching? Dieser Ansatz ist identisch mit dem, was Scott Hanselman hier beschreibt: http://www.hanselman.com/blog/MixMobileWebSitesWithASPNETMVCAndTheMobileBrowserDefinitionFile.aspx und er erwähnt es nicht. – roufamatic

2

Im Model-View-Controller-Muster ist es der Controller, der die Ansicht auswählt, daher ist es nicht so schlimm, eine if-Anweisung hinzuzufügen und eine entsprechende Ansicht zurückzugeben. Sie können die if-Anweisung in einer Methode kapseln und es nennen:

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

Alternativ können Sie einen Blick Motor erstellen, die eine Ansicht ausführt dynamisch basierend auf, ob es mobil oder nicht. Ich bin kein Fan von diesem Ansatz, da ich glaube, dass der Controller verantwortlich sein sollte. Wenn Sie zum Beispiel auf dem iPhone surfen, möchten Sie möglicherweise stattdessen die vollständige Desktop-Version sehen. Im ersten Ansatz würden Sie die entsprechende boolesche Flagge übergeben, aber im letzteren Fall werden die Dinge komplizierter.

0

Ihre Kernlogik sollte in den Controllern identisch sein und nur die Ansicht, die Sie benötigen, wird geändert, so dass Sie die if/else-Anweisung benötigen, um die richtige Ansicht für jede Controller-Aktion zu liefern.

Eine Alternative wäre, Sie Controller-Logik in einer separaten DLL zu wickeln und dann verschiedene Controller/Pfade für die mobile Version haben. Wenn ein regulärer Controller eine Anfrage von einem mobilen Gerät empfängt, können Sie diese in Ihren mobilen Bereich umleiten, der alle Ihre mobilen Controller enthält, die die gemeinsame Steuerungslogik verwenden. Diese Lösung ermöglicht es Ihnen auch, Tweeks durchzuführen, die spezifisch für die mobilen Controller sind und sich nicht auf Ihre normalen Controller auswirken.

1

Dies ist eine Version, die tatsächlich funktioniert, sowohl mit T4MVC als auch im Freigabemodus (in dem das Zwischenspeichern von Ansichten aktiviert ist). Es kümmert sich auch um Benutzerkontrollen und absolute/relative URLs. Es erfordert die Mobile Device Browser 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; 
    } 
} 
+0

Vielen Dank für das Nachschlagen, aber ich sehe immer noch nicht, warum Sie den Cache nicht vertrauen. AFAICT ermöglicht Caching sollte die Aufrufe in base.FindView() beschleunigen. Diese Anrufe werden ausgeführt, nachdem die richtige Ansicht ausgewählt wurde. Überprüfung mit Reflektor bestätigt. Ich kann verstehen deaktivieren Caching, wenn Sie erwarten, dass diese Ansichten ändern, aber das ist nicht, was hier passiert. Die Ansichten sind die gleichen, wir fügen nur Logik hinzu, um sie auszuwählen. Ich bleibe beim Cache. – roufamatic

2

Ich denke, dass der richtige Ort, um diese Funktionalität zu schließen, benutzerdefinierte ViewEngine ist. Aber Sie sollten wissen, wie IViewEngine.FindView Methode von der ViewEngineCollection aufgerufen wird (finden Sie mehr auf dieser here).

Aktualisiert solution vorgeschlagen von Scott Hanselman funktioniert nicht richtig. Sie können meine Beispielimplementierung dieses Ansatzes here finden. Lesen Sie die Readme-Datei, in der beschrieben wird, wie Sie falsches Verhalten wiederholen können.

schlage ich einen anderen Ansatz, wenn eine Ansicht überprüft nicht von Original Viewengine gefunden wurde und wenn useCache Parameter true ist, prüft sie, ob Ansicht mit dem Parameter in Original Viewengine existieren useCache=false.

Es ist zu komplex, den gesamten Code hier zu platzieren, aber Sie können den vorgeschlagenen Ansatz in meinem Open-Source-Spielplatz here implementiert finden. Überprüfen Sie MobileViewEngine Klassen- und Unit-Tests.

Einige MobileViewEngine Features:

  • funktioniert ordnungsgemäß mit Blick Caching und verwendet Cache Original-Ansicht-Engine.
  • Unterstützt beide: Aufnahmeansichtsnamen und relative Ansichtspfade (~/Ansichten/Index), die von der MvcContrib T4-Vorlage verwendet werden.
  • Resolves "Index" Ansicht wie folgt:
    • Mobile/Platform/Index - wenn Ansicht vorhanden ist, und ein mobiles Gerät Plattform (iPhone, Android etc.) wird in den unterstützten Liste eingetragen.
    • Mobile/Index - Ansicht für alle anderen mobilen Geräte. Wenn die Ansicht nicht vorhanden ist, können Sie optional auf die Desktop-Ansichtsversion zurückgreifen.
    • Index - für Desktop-Ansicht-Version.
  • können Sie mobile Ansichtshierarchie anpassen (z.B. Mobile/ Platform/Manufacturer) oder mobile Auflösung Anzeigen Pfad durch das Hinzufügen/Ändern von Geräteregeln (siehe MobileDeviceRule und PlatformSpecificRule).

Hope, wird diese

+0

+1 es hat geholfen, danke –