Search code examples
asp.netasp.net-mvc-4jquery-mobilewindows-ce

How to force Motorola 2180 mobile computer to be recognized as mobile device in ASP.NET MVC4 application


In ASP.NET MVC4 application

HttpContext.Current.Request.Browser.IsMobileDevice

is used to detect mobile devices. It returns false for MC2180.

Application contains views with .Mobile as part on view name for mobile devices. Those views are not rendered, regular browser views appear.

Application is browser application which renders different views in browser on mobile and non-mobile devices.

51 degrees mobi module from http://51degrees.codeplex.com/ free version is also installed.

If Motorola MC2180 mobile computer/handheld scanner is used to log on to application, is is not detected as mobile device: .Mobile views are not executed, usual views appears.

How to force it to be recognized as mobile device ? Device is running Windows CE 6.0 and it contains Motorola Rhoelements RHOS custom browser which returns version string as

Mozilla/5.0 (Windows CE 6.0) AppleWebKit/534.51 (KHTML, like Gecko) MotorolaWebKit/2.1.8.7 Safari/534.51

Application should in Mono and in ASP.NET 4. jQuery and jQuery-mobile are used in mobile views.


Solution

  • Based on the User Agent you've given, I've managed to get the device recognised as a mobile device using www.detectmobilebrowsers.com. It uses a Regex to evaluate the user agent and has many examples posted in various languages.

    I've adapted the example into a method that you can call;

    public bool DeviceIsMobile(string userAgent)
    {
      Regex regex1 = new Regex(@"(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino", RegexOptions.IgnoreCase | RegexOptions.Multiline);
      Regex regex2 = new Regex(@"1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-", RegexOptions.IgnoreCase | RegexOptions.Multiline);
    
      if ((regex1.IsMatch(userAgent) || regex2.IsMatch(userAgent.Substring(0, 4))))
      {
        return true;
      }
    
      return false;
    }
    

    And you can get the User Agent with;

    HttpContext.Current.Request.UserAgent
    

    MVC3

    You could write a custom ViewEngine to perform this check and automatically show the .Mobile.cshtml view. Scott Hanselman did a good post on how to write a mobile-aware ViewEngine - adapting this should get you what you need;

    public class MobileRazorViewEngine : RazorViewEngine
    {
      public override ViewEngineResult FindView(ControllerContext controllerContext, 
        string viewName, string masterName, bool useCache)
        {
          string userAgent = controllerContext.HttpContext.Request.UserAgent;
          string overrideViewName = DeviceIsMobile(userAgent) ? viewName + ".Mobile" : viewName;
    
          ViewEngineResult result = NewFindView(controllerContext, overrideViewName, masterName, useCache);
    
          // If we're looking for a Mobile view and couldn't find it try again without modifying the viewname
          if (overrideViewName.Contains(".Mobile") && (result == null || result.View == null))
          {
            result = NewFindView(controllerContext, viewName, masterName, useCache);
          }
    
          return result;
        }
    
        private ViewEngineResult NewFindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
          // Get the name of the controller from the path
          string controller = controllerContext.RouteData.Values["controller"].ToString();
          string area = "";
    
          try
          {
            area = controllerContext.RouteData.DataTokens["area"].ToString();
          }
          catch
          {
    
          }
    
          // Create the key for caching purposes           
          string keyPath = Path.Combine(area, controller, viewName);
    
          // Try the cache           
          if (useCache)
          {
            //If using the cache, check to see if the location is cached.               
            string cacheLocation = ViewLocationCache.GetViewLocation(controllerContext.HttpContext, keyPath);
    
            if (!string.IsNullOrWhiteSpace(cacheLocation))
            {
              return new ViewEngineResult(CreateView(controllerContext, cacheLocation, masterName), this);
            }
          }
    
          // Remember the attempted paths, if not found display the attempted paths in the error message.           
          var attempts = new List<string>();
    
          string[] locationFormats = string.IsNullOrEmpty(area) ? ViewLocationFormats : AreaViewLocationFormats;
    
          // for each of the paths defined, format the string and see if that path exists. When found, cache it.           
          foreach (string rootPath in locationFormats)
          {
            string currentPath = string.IsNullOrEmpty(area) ? string.Format(rootPath, viewName, controller) : string.Format(rootPath, viewName, controller, area);
    
          if (FileExists(controllerContext, currentPath))
          {
            ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, keyPath, currentPath);
    
            return new ViewEngineResult(CreateView(controllerContext, currentPath, masterName), this);
          }
    
          // If not found, add to the list of attempts.               
          attempts.Add(currentPath);
        }
    
        // if not found by now, simply return the attempted paths.           
        return new ViewEngineResult(attempts.Distinct().ToList());
      }
    }
    

    To use this, you need to add the ViewEngine to your App_Start and use;

    ViewEngines.Engines.Add(new MobileRazorViewEngine());
    

    MVC4

    As pointed out by Andrus, the above answer using ViewEngines is targeted towards MVC3. In MVC4, you could extend DefaultDisplayMode to write your own custom check for mobile;

    public class RegexMobileDisplay : DefaultDisplayMode
    {
      public RegexMobileDisplay() : base("Mobile")
      {
        ContextCondition = context => DeviceIsMobile(context.Request.UserAgent);
      }
    }
    

    And registering this in App_Start;

    DisplayModeProvider.Instance.Modes.Insert(0, new RegexMobileDisplay());
    

    I hope this helps.

    Matt