ASP.NET MVC 4 Mobile Features Deprecated Faster Than Appeared

    What is Mobile Features in ASP.NET MVC 4


    ASP.NET MVC 4 came out with a very expected and long-awaited new feature - what the English call Mobile Features - support for mobile devices. By and large, the name immediately surprised, as it slightly differs from the technical description of the innovation. But promotion - there is promotion. All references to page templates (layout) with support for HTML 5, specifying viewport, CSS media - all this is not directly related to the MVC framework.

    Only two points can be attributed to the new feature of the framework itself:
    • Creation of View and templates specific for mobile browsers
    • the ability to change on the fly which View will be rendered to the user - namely, switch in runtime between different View

    And here it is immediately worth noting that the word "mobile" is mentioned solely for advertising purposes. MVC 4 allows you to create multiple View for each of the required pages and determine for which browser each of them should be displayed. That is, the possibilities are by no means limited to mobile browsers.

    Everything ingenious is simple - a “hook” in ViewEngine


    The implementation of this feature is very simple. This is just a “hook” in ViewEngine.

    You make different pages (Views) for different devices or browsers. Name the files by adding the keyword:
    • Catalog.cshtml
    • Catalog.iPhone.cshtml

    Specify the criteria by which the desired View will be selected - using DisplayModeProvider, specify the desired DefaultDisplayMode with the desired name.

    DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("iPhone")
    {
        ContextCondition = (context => context.GetOverriddenUserAgent().IndexOf
             ("iPhone", StringComparison.OrdinalIgnoreCase) >= 0)
    });
    

    In runtime, when the controller method works, the prepared ViewResult is passed to the View Engine, the conditions of the DisplayModeProvider are checked, it changes the name of the View file that needs to be loaded.

    Can we really use this?


    Of course we can. But only in very simple cases. The main disadvantage is that all the Views that you make for the page are processed by the same controller method. Sooner or later, this becomes a problem.

    The time has come when the website should support browsers not only on desktop computers, laptops and mobile devices, but also on TVs. Moreover, mobile devices include ordinary phones, smartphones and tablet computers. And you must admit - if the appearance on the tablet and smartphone can still be the same, with the same JavaScript widgets, then for ordinary cell phones, of which there are many more, it is difficult to provide the same presentation and the same Web UI features.

    Support for both smartphones and tablets at first glance does not look so complicated - the difference in screen size. But over a larger area, you can place more information or more custom functions, and not just increase the size of the pictures.

    TV support is a very simple task. Full HD means the same screen size in pixels. But the pluses end there.

    It turns out that if your site was opened from a TV, it could be opened in browsers on:
    • Phillips Smart TV - NetTV SDK - CE-HTML Website
    • Samsung Smart TV - Samsung has its own SDK, the possibilities are very different from NetTV
    • LG Smart TV
    • with XBOX 360 - Internet Explorer
    • from the PlayStation 3
    • from Wii
    • with Google TV, Sony TVs with integrated Google TV
    • with Apple TV
    • Boxee box, Kylo browser, Roku and others

    To make the site version equally convenient for all these devices is a little realistic. If you want to take advantage of all the additional features that these devices provide you as developers, then it becomes not rational to do this in one version of the site. And some features, believe me, are worth using them.

    For example, XBOX runs the usual Internet Explorer, the width of the screen is quite sufficient to work with the usual desktop version of the site, but the user is forced to drag the cursor on the screen with the joystick. In order to press the button on the screen, he needs to move the cursor over it and press the button on the joystick. It becomes obvious that a more suitable interface is an interface for tablets, with large rectangular buttons. Comboboxes are also not convenient. Scrolling through the page on the joystick is quite convenient.

    On SmartTV, you have to rely on the fact that there is no cursor and the user runs through the buttons and inputs on the page by pressing the up / down / left / right buttons on the remote control. To support other buttons on the remote that simplify navigation, you will have to read the documentation from the SDK and write JavaScript specific to the device — the key codes are different.

    And this is only if you start to consider TVs. There are also many interesting things with smartphones and tablets, but this is a more common and frequently discussed topic.

    It is worth starting to work in this direction and the question quickly arises that the versions of sites for desktops, mobile devices and TVs should be different. And they should differ not only in View. There should be different models, which means that it is best when different controller methods work with them.

    What can be offered in return?


    It is clear that the simplest thing is to immediately create different sites for different devices and redirect to the right one. We discard such a solution as too simple. You can roll back to this option at any time.

    Of course, you can do different methods for different devices in the same controller, but I would like a more convenient and beautiful solution.

    Given the architecture of ASP.NET MVC 4, there is only one suitable option. Inside the MVC application (project), each of the site options must be executed in its Area. By User Agent String we can determine from which device / browser the request is received and send it to the desired Area.

    To transfer to the desired Area, you need to add a constraint (Constraint) for each route (Route) in the routing table.

    The disadvantage of this approach is that you should not forget to add such a restriction to all routes.

    For example, if we made an Area to redirect everyone to with a Chrome browser, then Area Registration would look like this:

      public class ChromeAreaRegistration : AreaRegistration
      {
        public override string AreaName
        {
          get { return "Chrome"; }
        }
        public override void RegisterArea(AreaRegistrationContext context)
        {
          context.MapRoute(
              "Chrome_default",
              "{controller}/{action}/{id}",
              new { controller = "Home", action = "Index", id = UrlParameter.Optional },
              new { isChromeBrowser = new IsChromeConstraint() }
          );
        }
      }
    

    In this case, the restriction will look like this:

      public class IsChromeConstraint : IRouteConstraint
      {
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
          string userAgent = httpContext.Request.UserAgent;
          if (string.IsNullOrWhiteSpace(userAgent)) { return false; }
          return userAgent.Contains("Chrome");
        }
      }
    

    At the same time, we have the main Area, where all other browsers should go, except for Chrome.

      public class DesktopAreaRegistration : AreaRegistration
      {
        public override string AreaName
        {
          get { return "Desktop"; }
        }
        public override void RegisterArea(AreaRegistrationContext context)
        {
          context.MapRoute(
              "Desktop_default",
              "{controller}/{action}/{id}",
              new { controller = "Home", action = "Index", id = UrlParameter.Optional },
              new { isNotChromeBrowser = new IsNotChromeConstraint() }
          );
        }
      }
    

    in it we should also use a restriction that filters browsers cutting off Chrome:

      public class IsNotChromeConstraint : IRouteConstraint
      {
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
          string userAgent = httpContext.Request.UserAgent;
          if (string.IsNullOrWhiteSpace(userAgent)) { return false; }
          return !userAgent.Contains("Chrome");
        }
      }
    

    It is necessary to set restrictions for all routes in all Area, despite the fact that routes in runtime are viewed from top to bottom. The fact is that the procedure for registering AreaRegistration at startup is random. This can be avoided by registering the routes of all Area in one place - in Global.asax - by explicitly indicating their order. Then you can guarantee that the check for Chrome browser will always occur first.

    P.S


    If you get tired of this, you can always easily move each Area into a separate application and host on different domains.

    Also popular now: