Thursday, September 26, 2013

Working with Tridion and ASP .Net 4 Mobile

In this post I would like to introduce some concepts about how to use the new mobile capabilities of ASP .Net 4 and Tridion. ASP .Net 4 brings a nice feature called display modes where we can define specific views for display modes without changing the controllers. Additionally Tridion brings a new feature called Context Engine Cartridge (CEC) this new feature uses Ambient Data Framework to put context specific information in the form of claims.

ASP .Net 4 Display Modes

ASP .Net 4 comes with two display modes by default (default and mobile), they are determined by the Razor View Engine which is responsible to determine if the request is coming from a mobile device or not. This feature is very simple and powerful, let's put some examples.

Imagine you want to define two different versions of a razor view, one for regular browsers and one for mobile browsers, if that is the case you will need to follow this rules.

Default View Name: Index.cshtml
Mobile View Name: Index.mobile.cshtml

It means that we just need to add the "mobile" word after the regular view name. The Razor View Engine will use the home.mobile.cshtml view if the requests comes from a mobile device. If we want to integrate this feature with Tridion we just need to create two pages using the same page template (cshtml extension) but using different content, metadata and logic which should be specific for mobile or regular pages.







I have this simple code in my Controller as you can see, the same code will work for both of them.

public class HomeController : Controller {
    public ActionResult Index() {          
        return View();
    }
}

Here the result in a regular desktop browser.








Here the result in a mobile browser.



Adding Custom Display Modes

Additionally to the default and mobile display modes, ASP .Net 4 allows us to define custom display modes for specific devices and browsers, in this example I will add an iPhone specialized view.



In order to define an specialized display mode so that the Razor View Engine will use the index.iphone.cshtml view when the request is coming from an iPhone we will insert a new Display Mode in the Global.asax

Here a code sample.

protected void Application_Start() {
    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);

    DefaultDisplayMode iPhoneDisplayMode = new DefaultDisplayMode("iPhone");
    iPhoneDisplayMode.ContextCondition = (HttpContextBase context) => {
         return context.GetOverriddenUserAgent().IndexOf("iPhone", StringComparison.OrdinalIgnoreCase) != -1;
    };

    DisplayModeProvider.Instance.Modes.Insert(0, iPhoneDisplayMode);
}

In the code sample I am declaring a new display mode called "iPhone" this will directly map with the view name it will lead to a view called index.iphone.cshtml. Other important point in this code is the ContextCondition property which is a delegate that is executed for each view that is being requested by the Razor View Engine, this delegate should point to a boolean function. In the sample I am checking if the User Agent contains the word "iPhone". Additionally we should insert it as the first one. The rule is that the most specific display modes should be inserted first and the less specific last.

Context Engine Cartridge

There is a very nice feature that was recently added to the Tridion technology stack. This feature is similar to Wurfl or Device Atlas with the difference that is integrated with Tridion via Ambient Data Framework using a Cartridge that will make all the device context information available in the Claim Store.

Context Engine Cartridge uses "Aspects" to divide information, CEC comes with 3 aspects out of the box "device", "browser" and "os".

Claims are identified following this naming convention.

Uri claimUri = new Uri("taf:claim:context:<ASPECTNAME>:<PROPERTYNAME>");

I have updated the custom Display Mode for iPhone devices code to use CEC.

DefaultDisplayMode iPhoneDisplayMode = new DefaultDisplayMode("iPhone");
iPhoneDisplayMode.ContextCondition = (HttpContextBase context) => {
    ClaimStore claimStore = AmbientDataContext.CurrentClaimStore;
    Uri mobileUri = new Uri("taf:claim:context:device:mobile");
    Uri modelUri = new Uri("taf:claim:context:device:model");

    bool isMobile = claimStore.Get<string>(mobileUri).AsBool();
    string model = claimStore.Get<string>(modelUri);

    return isMobile && model.Equals("iPhone");
};

DisplayModeProvider.Instance.Modes.Insert(0, iPhoneDisplayMode);


In the code above I am accessing to the ClaimStore in the ContextCondition delegate and checking the mobile and model device properties.

Here how the page is looking in an iPhone screen.



2 comments:

  1. Almost what i was doing, Nuno's wrapper can simplify this a bit:

    using Sdl.Tridion.Context;

    DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("Mobile")
    {
    ContextCondition = context => new ContextEngine().Device.IsMobile
    });

    Also, i wonder that's the scope of ContextEngine (and AmbientDataContext.CurrentClaimStore for that matter): session, request? Intuitively, it's obvious that claims store must be accessed within lambda, hence wrapper using them must be instantiated there too.

    ReplyDelete
  2. I agree with you...the way we look at clown needs to be changed. The experience you had in Japan must be a learning experience for you. Some of the Japanese must have shown hatred buy they must have shown respect to you as well. cell phone detector

    ReplyDelete