27 votes

Comment pourrais-je le Changer ASP.NET MVC Vues Basées sur le Type de Périphérique?

Je suis en train de travailler mon chemin à travers certains ASP.NET MVC lecture et j'ai une application web au travail que je vais être la migration de WebForms à la MVC. L'une des demandes de fonctionnalités-je m'attendre à obtenir dans le processus est d'avoir une vue simplifiée retourné si l'utilisateur est à venir à partir d'un appareil mobile.

Je n'arrive pas à voir où est le meilleur endroit est de mettre en œuvre ce type de logique. Je suis sûr qu'il ya une meilleure façon que l'ajout d'un if/else pour le Navigateur.IsMobileDevice dans toutes les actions qui renvoie une vue. Quel type d'options que j'ai à faire cela?

21voto

Dale Ragan Points 14495

Mise à jour: Cette solution a un bug subtil. Le framework MVC remet en FindView/FindPartialView deux fois: une fois avec useCache=true, et si ce n'est pas de retourner un résultat, une fois avec useCache=false. Car il n'y a qu'un seul cache pour tous les types de points de vue, les utilisateurs mobiles peuvent voir les vues du bureau si un navigateur de bureau, a été la première à arriver.

Pour ceux qui s'intéressent à l'aide des moteurs de visualisation pour résoudre ce problème, Scott, Hanselman a mis à jour sa solution ici:

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

(Mes excuses pour la réponse détourner, je ne veux pas que quiconque d'avoir à passer par ce!)

Édité par roufamatic (2010-11-17)


La première chose que vous voulez faire est de présenter l' Appareil Mobile du Navigateur de Fichiers à votre projet. À l'aide de ce fichier, vous pouvez cibler ce que jamais l'appareil que vous souhaitez prendre en charge, sans avoir à connaître les détails de ce que ces dispositifs envoyer dans leurs en-têtes. Ce fichier a déjà fait le travail pour vous. Vous utilisez ensuite la Demande.Navigateur propriété d'adapter la vue qui vous voulez retourner.

Ensuite, venir avec une stratégie sur la façon dont vous voulez organiser vos vues dans le dossier Vues. Je préfère laisser la version de bureau à la racine et ensuite avoir un Mobile dossier. Par exemple, la vue d'Accueil dossier devrait ressembler à ceci:

  • La maison
    • Mobile
      • iPhone
        • Index.aspx
      • BlackBerry
        • Index.aspx
    • Index.aspx

Je suis en désaccord avec @Mehrdad sur l'utilisation d'un affichage personnalisé du moteur. Le moteur d'affichage sert plus d'un but et un seul de ces objectifs est de trouver des points de vue pour le contrôleur. Vous faites cela en remplaçant la FindView méthode. Dans cette méthode, vous pouvez faire vos vérifications sur les lieux où trouver de la vue. Une fois que vous savez quel appareil à l'aide de votre site, vous pouvez utiliser la stratégie de toi pour l'organisation de votre point de vue pour revenir à la vue de cet appareil.

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

Le code ci-dessus vous permet de régler l'affichage en fonction de votre stratégie. L'automne est de retour à la vue du bureau, si aucune vue n'a été trouvé pour le périphérique ou si il n'y a pas un défaut de la vue mobile.

Si vous décidez de mettre de la logique dans votre contrôleur, au lieu de créer un moteur d'affichage. La meilleure approche serait de créer un personnalisé ActionFilterAttribute que vous pouvez décorer votre contrôleur avec. Puis remplacer le OnActionExecuted méthode pour déterminer l'appareil qui est de l'affichage de votre site. Vous pouvez le vérifier sur ce blog sur la façon d'. Le post a aussi quelques jolies quelques liens de Mélanger des vidéos sur ce sujet.

2voto

Mehrdad Afshari Points 204872

Dans le Modèle-Vue-Contrôleur patron, c'est le contrôleur qui choisit de vue, donc, il n'est pas mauvais pour ajouter un if déclaration et de retourner une vue appropriée. Vous pouvez encapsuler l' if déclaration d'une méthode et de l'appeler:

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

Alternativement, vous pouvez créer un moteur d'affichage dynamique qui exécute une vue basée sur le fait qu'il est mobile ou non. Je ne suis pas un fan de cette approche, car je crois que le contrôleur doit être en charge. Par exemple, si vous naviguez sur l'iPhone, vous pouvez voir l'intégralité de la version de bureau à la place. Dans la première approche, vous souhaitez passer à la appropriée indicateur booléen, mais dans la dernière, les choses deviennent plus compliquées.

2voto

Andrej Golcov Points 409

Je pense que le droit de place pour brancher cette fonctionnalité est personnalisé ViewEngine. Mais vous devez être conscient de la façon dont IViewEngine.FindView méthode est appelée par l' ViewEngineCollection (en savoir plus sur ce ici).

Mise à jour de la solution proposée par Scott, Hanselman ne fonctionne pas correctement. Vous pouvez trouver mon exemple de mise en œuvre de cette approche ici. Vérifier le fichier readme qui explique comment vous pouvez répéter un comportement incorrect.

Je suggère une autre approche qui vérifie si un point de vue n'a pas été trouvé par original ViewEngine et si useCache paramètre true, il vérifie si la vue existe pas dans l'original ViewEngine avec le paramètre useCache=false.

Il est trop complexe à mettre tout le code ici, mais vous pouvez trouver l'approche suggérée mises en œuvre dans mon open-source aire de jeux ici. Vérifiez MobileViewEngine de la classe et de l'unité des tests.

Certains MobileViewEngine caractéristiques:

  • Fonctionne correctement avec vue de la mise en cache et utilise d'origine du moteur d'affichage de cache.
  • Supporte à la fois: plan d'afficher les noms et relative chemins de vue (~/Views/Index) utilisé par MvcContrib modèle T4.
  • Résout "Index" afficher comme suit:
    • Mobile/Platform/Index – si la vue existe et une plate-forme mobile (IPhone, Android, etc.) est enrôlé dans la liste.
    • Mobile/Index - vue pour tous les autres appareils mobiles. Si la vue n'existe pas, vous pouvez éventuellement secours à la vue du bureau version.
    • Index – pour l'affichage de bureau version.
  • Vous pouvez personnaliser la vue mobile de la hiérarchie (par exemple, Mobile/ Platform/Manufacturer) ou de personnaliser la vue mobile de résolution de chemin en ajoutant/modifiant les règles d'appareil (voir MobileDeviceRule et PlatformSpecificRule).

L'espoir, cela vous aide à

1voto

Carl Hörberg Points 2786

Ceci est une version qui fonctionne réellement, à la fois avec T4MVC et en mode release (où la mise en cache des points de vue est activée). Il prend soin de usercontrols et absolue/relative des url en tant que bien. Il exige l' Appareil Mobile du Navigateur de Fichiers.

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

0voto

Kelsey Points 26456

Votre cœur de la logique devrait être la même dans les contrôleurs et que le point de vue dont vous avez besoin sera changer si le contrôleur est l'endroit où vous avez besoin de la if/else pour servir la vue correcte pour chaque contrôleur de l'action comme vous l'avez indiqué.

Une autre solution serait de vous envelopper de contrôleur de logique dans une dll séparée et ensuite les différents contrôleurs / les chemins pour la version mobile. Si un contrôleur reçoit une demande à partir d'un appareil mobile, vous pouvez les rediriger vers votre mobile zone qui contient tous les contrôleurs qui utilisent le contrôleur partagé logique. Cette solution permettrait également de faire "tweeks" qui sont spécifiques au mobile contrôleurs et ne pas avoir d'impact régulièrement vos contrôleurs.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X