Question

Je travaille mon chemin à travers une lecture ASP.NET MVC et j'ai une application web au travail que je migrerons de WebForms à MVC. L'une des demandes de fonctionnalités que je compte obtenir dans le processus est d'avoir une vue simplifiée retourné si l'utilisateur provient d'un appareil mobile.

Je ne peux pas tout à fait voir où le meilleur endroit est de mettre en œuvre ce type de logique. Je suis sûr qu'il ya une meilleure façon que d'ajouter un if / else pour Browser.IsMobileDevice dans toutes les actions qui retourne une vue. Quel genre d'options que je dois faire?

Était-ce utile?

La solution

Mise à jour : Cette solution a un bug subtil. Le framework MVC appellera dans FindView / FindPartialView deux fois: une fois avec useCache=true, et si cela ne revient pas à un résultat, une fois avec useCache=false. Comme il n'y a qu'un seul cache pour tous les types de vues, les utilisateurs mobiles peuvent finir par voir des vues de bureau si un navigateur de bureau a d'abord été d'arriver.

Pour les personnes intéressées à l'aide de moteurs d'affichage personnalisé pour résoudre ce problème, Scott Hanselman a mis à jour sa solution ici:

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

(Toutes mes excuses pour le hijack de réponse, je ne veux pas que quelqu'un d'autre d'avoir à passer par cela!)

Edité par roufamatic (17/11/2010)


La première chose que vous voulez faire est d'introduire le Mobile Device File Browser à votre projet. En utilisant ce fichier, vous pouvez cibler ce que jamais périphérique que vous souhaitez soutenir sans avoir à connaître les détails de ce que ces dispositifs envoient dans leurs têtes. Ce fichier a déjà fait le travail pour vous. Vous utilisez ensuite la propriété Request.Browser pour adapter la vue que vous souhaitez revenir.

Ensuite, venir avec une stratégie sur la façon dont vous voulez organiser votre point de vue dans le dossier Vues. Je préfère laisser la version de bureau à la racine, puis un dossier mobile. Par exemple, le dossier View Home ressemblerait à ceci:

  • Accueil
    • Mobile
      • iPhone
        • Index.aspx
      • BlackBerry
        • Index.aspx
    • Index.aspx

Je suis en désaccord avec @Mehrdad sur l'utilisation d'un moteur de vue personnalisée. Le moteur de vue sert plus d'un but et un de ces objectifs est de trouver des vues pour le contrôleur. Vous faites cela en redéfinissant la méthode FindView. Dans cette méthode, vous pouvez faire vos chèques sur où trouver la vue. Une fois que vous savez quel appareil utilise votre site, vous pouvez utiliser la stratégie que vous est venu avec pour l'organisation de votre point de vue de retourner la vue de ce périphérique.

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 définir la vue en fonction de votre stratégie. Le dos de l'automne est la vue de bureau, si aucune vue n'a été trouvé pour l'appareil ou s'il n'y a pas une vue mobile par défaut.

Si vous décidez de mettre la logique dans votre contrôleur de lieu de créer un moteur de vue. La meilleure approche serait de créer une coutume ActionFilterAttribute que vous pouvez décorer votre contrôleur est avec. Ensuite, passer outre la méthode OnActionExecuted pour déterminer quel appareil consulte votre site. Vous pouvez vérifier ce post sur comment. Le poste a aussi quelques liens sympas à des vidéos Mix sur ce sujet.

Autres conseils

Dans le modèle Model-View-Controller, il est le contrôleur qui choisit point de vue, donc, il est pas si mal d'ajouter une déclaration if et retourner une vue appropriée. Vous pouvez résumer la déclaration de if dans une méthode et l'appeler:

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

Vous pouvez créer un moteur de vue qui exécute dynamiquement une vue basée sur que ce soit mobile ou non. Je ne suis pas fan de cette approche car je crois que le contrôleur devrait être en charge. Par exemple, si vous naviguez sur l'iPhone, vous pouvez voir la version complète de bureau à la place. Dans l'ancienne approche, vous devriez passer le drapeau booléen approprié, mais dans ce dernier, les choses deviennent plus compliquées.

Je pense que le bon endroit pour brancher cette fonctionnalité est ViewEngine sur mesure. Mais vous devez être conscient de la façon dont la méthode IViewEngine.FindView est appelée par le ViewEngineCollection (trouver plus sur ce ).

href="http://www.hanselman.com/blog/ABetterASPNETMVCMobileDeviceCapabilitiesViewEngine.aspx" Mise à jour proposée par Scott Hanselman ne fonctionne pas correctement. Vous pouvez trouver mon exemple d'implémentation de cette approche . Vérifiez le fichier readme qui décrit comment vous pouvez répéter un comportement incorrect.

Je suggère une autre approche qui vérifie si une vue n'a pas été trouvé par ViewEngine d'origine et si le paramètre useCache est true, il vérifie si vue existent dans ViewEngine d'origine avec le paramètre useCache=false.

Il est trop complexe pour mettre tout le code ici mais vous pouvez trouver l'approche suggérée mis en œuvre dans mon terrain de jeu open-source ici . Vérifiez classe MobileViewEngine et tests unitaires.

Certaines fonctionnalités MobileViewEngine:

  • fonctionne correctement avec vue la mise en cache et utilise le cache du moteur de vue original.
  • Prend en charge les: noms de vue prises et les chemins de vue relatifs (~ / vues / Index) utilisé par modèle MvcContrib T4
  • .
  • Résout "Index" vue comme suit:
    • Mobile/Platform/Index -. Si la vue existe et une plate-forme de l'appareil mobile (iPhone, Android, etc.) est engagé dans la liste soutenue
    • Mobile/Index - vue pour tous les autres appareils mobiles. Si la vue n'existe pas que vous pouvez en option fallback pour afficher la version de bureau.
    • Index - pour afficher la version de bureau.
  • Vous pouvez personnaliser la hiérarchie mobile vue (par exemple Mobile/ Platform/Manufacturer) ou personnaliser la résolution de chemin de vue mobile en ajoutant / la modification des règles de l'appareil (voir MobileDeviceRule et PlatformSpecificRule).

L'espoir, cela vous aidera

Ceci est une version qui fonctionne réellement, à la fois avec T4MVC et en mode de libération (où la mise en cache de vues est activée). Il ne prend soin de usercontrols et urls absolu / relatif aussi bien. Il exige que le Mobile Device Browser fichier.

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

Votre logique de base doit être le même dans les contrôleurs et que la vue dont vous avez besoin de changer de sorte que le contrôleur est là que vous avez besoin d'if / else instruction pour servir la vue correcte pour chaque action du contrôleur que vous avez déclaré.

Une alternative serait de vous envelopper la logique de commande dans une dll séparée et ensuite différents contrôleurs / chemins pour la version mobile. Si un contrôleur régulier reçoit une demande d'un appareil mobile, vous pouvez les rediriger vers votre région mobile qui contient tous vos contrôleurs mobiles qui utilisent la logique du contrôleur partagé. Cette solution vous permettra également de faire « tweeks » qui sont spécifiques aux contrôleurs mobiles et ne pas l'avoir un impact sur vos contrôleurs réguliers.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top