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);
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.
Almost what i was doing, Nuno's wrapper can simplify this a bit:
ReplyDeleteusing 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.
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