asp.net-mvcvb.netwurfldisplaymode

DisplayModeProvider issues


Using DisplayModeProvider to choose between views for "Desktop", "Tablet" and "Phone" in a MVC5 web application. It is my understanding that this class selects the correct provider in order and uses the first provider that returns True. However, when I step through the code, I find there is a repeated cycle through the code (it goes through multiple times, sometimes over 10 cycles) before deciding on the proper mode. I'm using WURFL Cloud for device detection. Lastly, I've started caching WURFL results in a Session variable. Thinking there must be something wrong with my code and/or logic. It's in VB.net since it's an evolution of a legacy project. The first block of code is in Application_Start in global.asax. Before it was in a separate class, but moved it to global.asax in an attempt to solve this problem.

DisplayModeProvider.Instance.Modes.Clear()
DisplayModeProvider.Instance.Modes.Add(New DefaultDisplayMode("Phone") With {.ContextCondition = Function(c) c.Request.IsPhone})
DisplayModeProvider.Instance.Modes.Add(New DefaultDisplayMode("Tablet") With {.ContextCondition = Function(c) c.Request.IsTablet})
DisplayModeProvider.Instance.Modes.Add(New DefaultDisplayMode("") With {.ContextCondition = Function(c) c.Request.IsDesktop})

My understanding is the function would check for each context condition and stop at the first one that is true. However, as mentioned above the code repeatedly executes even though one of the functions returns True.

Here are the extension methods I'm using. They reside in a module. The error handling code was added after a "perceived" outage of the WURFL cloud. Each is decorated with the following: System.Runtime.CompilerServices.Extension

Public Function IsPhone(request As HttpRequestBase) As Boolean
    Dim ans As Boolean
    Try
        If Not HttpContext.Current.Session("IsPhone") Is Nothing Then
            ans = HttpContext.Current.Session("IsPhone")
        Else
            wsm = New WURFLServiceModel(New     HttpContextWrapper(HttpContext.Current))
            ans = wsm.IsPhone
            HttpContext.Current.Session("IsPhone") = ans
        End If
    Catch ex As Exception
        ...
    End Try
    Return ans
End Function

Public Function IsTablet(request As HttpRequestBase) As Boolean
    Dim ans As Boolean
    Try
        If Not HttpContext.Current.Session("IsTablet") Is Nothing Then
            ans = HttpContext.Current.Session("IsTablet")
        Else
            wsm = New WURFLServiceModel(New HttpContextWrapper(HttpContext.Current))
            ans = wsm.IsTablet
            HttpContext.Current.Session("IsTablet") = ans
        End If
    Catch ex As Exception
        ...
    End Try
    Return ans
End Function

Public Function IsDesktop(request As HttpRequestBase) As Boolean
    Return True
End Function

Here is the code for the WURFLServiceModel

Imports ScientiaMobile.WurflCloud.Device

Public Class WURFLServiceModel

    Private mIsIOS As Boolean
    Private mIsTablet As Boolean
    Private mIsPhone As Boolean
    Private mResponse As String
    Private mErrors As Dictionary(Of String, String)

    Private api_Key As String = "xxxxxxxxxxxxxxxxxxxxxxxxxx"

    Public Sub New(ByVal request As HttpContextBase)
        GetDataByRequest(request)
    End Sub

    Public Sub GetDataByRequest(context As HttpContextBase)

        Dim config = New DefaultCloudClientConfig(api_Key)
        Dim manager = New CloudClientManager(config)
        Dim info = manager.GetDeviceInfo(context)
        mIsIOS = info.Capabilities("is_ios")
        mIsPhone = info.Capabilities("is_smartphone")
        mIsTablet = info.Capabilities("is_tablet")
        mBrandName = info.Capabilities("brand_name")
        mModelName = info.Capabilities("model_name")
        mErrors = info.Errors
        mResponse = info.ResponseOrigin

    End Sub

    Public ReadOnly Property IsDesktop As Boolean
        Get
            Return True
        End Get
    End Property

    Public ReadOnly Property IsIOS As Boolean
        Get
            Return mIsIOS
        End Get
    End Property

    Public ReadOnly Property IsTablet As Boolean
        Get
            Return mIsTablet
        End Get
    End Property

    Public ReadOnly Property IsPhone As Boolean
        Get
            Return mIsPhone
        End Get
    End Property

Although the application runs without error, I can't believe the cycling through this routine should be happening. Would like to clear it up, if possible. What am I doing wrong? Many thanks in advance!


Solution

  • As I see it, the issue has more to do with the internal implementation of MVC display modes than the WURFL API. The code bound to the display mode delegate is called back by ASP.NET MVC for each request to render a view, including partial views. This obviously results in multiple calls being made to the WURFL API. In addition, the WURFL Cloud API takes a while to respond because it has to make a HTTP request to the cloud, parse a cookie, and figure out details. The WURFL Cloud is clearly slower than the on-premise WURFL API which uses a direct access memory cache to pick up details of the user agent. I have used WURFL and MVC in a number of web sites and just went through this. For most of such sites I managed to get an on-premise license. As for the cloud, some per-request internal caching perhaps within your WURFLServiceModel class would be helpful so that you end up making a single cloud request for each rendering of the view. I don't particularly like the use of Session, but yes that could just be me. Session is still an acceptable way of do the "internal caching" I was suggesting above.