ASP.NET MVC 4 Mobile Features устарели быстрее чем появились

в 9:27, , рубрики: .net, ASP.NET, asp.net mvc 4, Блог компании «Дневник.ру», Веб-разработка, метки: , ,

Что такое Mobile Features в ASP.NET MVC 4

ASP.NET MVC 4 вышел с очень ожидаемой и долгожданной новой возможностью — то, что по английски называют Mobile Features — поддержкой мобильных устройств. По большому счету, название сразу удивило, так как немного расходится с техническим описанием нововведения. Но промоушен — есть промоушен. Все упоминания про шаблоны страниц (layout) с поддержкой HTML 5, указание viewport, CSS media — все это к MVC фреймворку непосредственно отношения не имеет.

К новой возможности самого фреймворка можно отнести только два пункта:

  • создание View и шаблонов специфичных для мобильных браузеров
  • возможность на лету изменять то, какое View будет рендерится пользователю — а именно переключаться в рантайме между различными View

И здесь сразу стоит заметить, что слово «мобильный» упоминается исключительно в рекламных целях. MVC 4 позволяет создавать несколько View для каждой из требуемых страниц и определять для какого браузера каждая из них должна показываться. То есть, возможности ни коем образом не ограничиваются именно мобильными браузерами.

Все гениальное просто — «hook» во ViewEngine

Реализация данной возможности очень проста. Это просто «hook» во ViewEngine.

Вы делаете разные страницы (Views) для разных устройств или браузеров. Именуете файлы добавляя ключевое слово:

  • Catalog.cshtml
  • Catalog.iPhone.cshtml

Задаете критерий по которому будет выбираться нужная View — пользуясь DisplayModeProvider задаете нужные DefaultDisplayMode с нужным именем.

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

В рантайме, когда отработает метод контроллера, подготовленный ViewResult передается во View Engine, проверяются условия DisplayModeProvider-a, он изменяет имя файла View, которое нужно загрузить.

Можем ли мы этим реально пользоваться?


Можем конечно. Но только в очень простых случаях. Основное неудобство именно в том, что все View, которые вы делаете для страницы обрабатываются одним и тем же методом контроллера. Рано или поздно, это становится проблемой.

Уже настало время, когда веб-сайт должен поддерживать браузеры не только на десктопных компьютерах, ноутбуках и мобильных устройствах, но еще и на телевизорах. Причем к мобильным устройствам относятся обычные телефоны, смартфоны и планшетные компьютеры. И согласитесь — если внешний вид на планшете и смартфоне еще может быть одинаковым, с одними и теми же JavaScript виджетами, то для обычных сотовых телефонов, коих еще много, такое же представление и такие же возможности Web UI обеспечить сложно.

Поддержка одновременно смартфонов и планшетов с первого взгляда выглядит не такой сложной — разница в размере экрана. Но на большей площади можно разместить больше информации или больше пользовательских функций, а не просто увеличить размер картинок.

Поддержка телевизоров выглядит очень простой задачей. Full HD означает одинаковый размер экрана в пикселах. Но на этом плюсы заканчиваются.

Оказывается, если Ваш сайт открыли с телевизора, он мог быть открыт в браузерах на:

  • телевизоре Phillips Smart TV — NetTV SDK — сайт на CE-HTML
  • телевизоре Samsung Smart TV — у Самсунга свое SDK, возможности сильно отличаются от NetTV
  • телевизоре LG Smart TV
  • с приставки XBOX 360 — Internet Explorer
  • с приставки PlayStation 3
  • с приставки Wii
  • с Google TV, телевизоры Sony со встроенным Google TV
  • с Apple TV
  • Boxee box, Kylo browser, Roku и другие

Сделать версию сайта одинаково удобную для всех этих устройств мало реалистично. Если вы хотите воспользоваться всеми дополнительными возможностями, которые эти устройства предоставляют Вам как разработчикам — то делать это в одной версии сайта становится не рационально. А некоторые возможности, поверьте, стоят того, чтобы ими пользоваться.

Например, на XBOX работает обычный Internet Explorer, ширина экрана вполне достаточная для работы с обычной десктопной версией сайта, но пользователь вынужден на джойстике возить по экрану курсор. Для того, чтобы нажать на кнопку на экране ему требуется навести на нее курсор и нажать кнопку на джойстике. Становится очевидным, что более подходящий интерфейс — это интерфейс для планшетов, с большими прямоугольными кнопками. Комбобоксы также не удобны. Пролистывать страницу на джойстике достаточно удобно.

На SmartTV Вам придется расчитывать на то, что нет курсора и пользователь бегает по кнопкам и инпутам на странице нажимая кнопки вверх/вниз/влево/вправо на пульте. Чтобы поддерживать другие кнопки на пульте, которые упрощают навигацию, придется прочитать документацию из SDK и писать JavaScript специфичный для конретного устройства — key codes разные.

И это только если начать рассматривать телевизоры. Со смартфонами и планшетами также много интересного, но это более распространенная и часто обсуждаемая тема.

Стоит начать работать в этом направлении и очень быстро встает вопрос о том, что версии сайтов для десктопов, мобильных устройств и телевизоров должны быть различными. И различаться должны не только во View. Должны быть разные модели, а значит лучше всего, когда с ними работают разные методы контроллеров.

Что можно предложить взамен?

Понятно, что самое простое — сразу сделать разные сайты для разных устройств и редиректить на нужный. Откинем такое решение как слишком простое. К этому варианту можно откатиться в любой момент.

Можно конечно делать для разных устройств разные методы в одном и том же контроллере, но хотелось бы более удобного и красивого решения.

Учитывая архитектуру ASP.NET MVC 4, есть только один подходящий вариант. Внутри MVC приложения (проекта), каждый из вариантов сайта должен быть выполнен в своей Area. По User Agent String мы может определить от какого устройства/браузера поступает запрос и направить его в нужную Area.

Чтобы переправить в нужную Area нужно для кажого маршрута (Route) в таблице рутинга добавить ограничение (Constraint).

Минус такого подхода в том, что такое ограничение нужно не забыть добавить во все маршруты.

Например, если мы сделали Area в которую нужно перенаправлять всех с Chrome browser, то Area Registration будет выглядеть так:

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

При этом ограничение будет выглядеть так:

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

При этом у нас есть основная Area, куда должны направляться все остальные браузеры, кроме Хрома.

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

в ней мы также должны использовать ограничение, которое фильтрует браузеры отсекая Хром:

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

Выставлять ограничения для всех маршрутов во всех Area необходимо, несмотря на то, что маршруты в рантайме просматриваются сверху вниз. Дело в том, что порядок регистрации AreaRegistration при старте случайный. Этого можно избежать, если регистрировать маршруты всех Area в одном месте — в Global.asax — явно указывая их порядок. Тогда можно гарантировать, что проверка на Хром браузер всегда будет происходить первой.

Постскриптум

Если Вам это надоест, вы всегда можете легко вынести каждую Area в отдельное приложение и хостить на разных доменах.

Автор: shirmanov

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js