One Way to Create Mobile Version Of Composite C1 Site

Topics: General
Mar 15, 2012 at 8:56 PM

I needed to create a mobile version of my C1 site.  Meaning, I need to show BOTH different content and different styles for the mobile site.

I was able to piece together a plan by looking at the different postings here, but I thought I'd post my final solution for either a) a reference for someone trying to do the same thing or b) critique by someone who has a better way of doing this.  I'm open to any and all suggestions on easier/better ways of approaching this issue.

The Plan

First, I decided that I was going to use one install of C1, and add multiple websites to that instance.  One for regular web, one for mobile.  Then, I used the Hostnames settings (new in Version 3) to map each site's homepage to a different host name.  (www.mysite.com for the regular site, m.mysite.com for the mobile site.)  I updated the settings in IIS and DNS so that everything is pointing to the right place.

Then, I decided I would, somehow, write a function to redirect a user on a mobile device to the mobile version.

The Redirect

I don't know a thing about XSLT, and I think there was a way to use that, but I didn't know where to start.  So I decided to write a custom C# inline function.  The function takes one input parameter (the page I want to redirect to), then checks to see if the user is using a mobile device.  If so, it redirects to the mobile version of that page, which is passed in as an input parameter.

Here's the function:

 

using System;
using System.Web;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using Composite.Data;
using Composite.Data.Types;

namespace MySite
{
	public static class InlineMethodFunction
	{
		public static bool RedirectToMobile(string RedirectPage)
		{
			bool IsMobi;
            IsMobi = HttpContext.Current.Request.Browser.IsMobileDevice;

            if (IsMobi)
            {
                HttpResponse hp = HttpContext.Current.Response;
                hp.Redirect(RedirectPage);
            }
            return IsMobi;
		}
	}
}

 

To get the function to work I needed to add a reference to the System.Web DLL from the Assembly References tab.

Then, in the head of each page of the regular site, I inserted the function:

 

		<f:function xmlns:f="http://www.composite.net/ns/function/1.0" name="MySite.RedirectToMobile">
			<f:param name="RedirectPage" value="http://m.Mysite.com/pageName" />
		</f:function>

 

 

IsMobileDevice?

This method uses the built in .NET property

HttpContext.Current.Request.Browser.IsMobileDevice

It turns out this isn't all that accurate.  My Blackberry was not detected as a mobile device.

So, after some more Googling, I found this:

http://51degrees.codeplex.com/

which is a marginally open source project that, long story short, makes some of those built in .NET properties like isMobileDevice more accurate.

The instructions for that project (located here: http://51degrees.mobi/Support/Documentation/Foundation/UserGuide.aspx) are not very good, as it seems the project is mostly geared toward getting you to pay for their premium version.

To get this 51 Degrees thing to work you have to:

1) Download their project (link above), build the project to create the DLL, put that DLL in your Composite Installation's Bin folder

2) Create a config file like they describe in the user guide.  Note that most of the config file (redirects, locations) is not necessary if you only want the more accurate IsMobileDevice data. The only part I included in my config file was the logging.  I put my config file in the app_data folder since I hate adding crap to my Web.Config file.

3) Update your web.config as described in the guide (Section 2.4)

4) Restart IIS.

Now, when I go to a page on my regular site (www.mysite.com/whatever) on a mobile device, it redirects to m.mysite.com/mobilewhatever.

Coordinator
Mar 16, 2012 at 12:56 PM
Edited Mar 16, 2012 at 3:44 PM

Hi @jpk

Thank you for sharing the experience here. With some polishing it is a good idea for a package, as a some people here were interested in knowing how to have such a setup.

I have some suggestions to make the solution more usable:

Even though content is different, I suspect it is similar, so editor would always have to take in account that there's always 1 more page that has to be edited. If I understood it correctly, you're manually inserting redirect code to each page. It can be optimized by f.e. having a meta data field which whould contain a page reference rather than a string with a url. Then you can add the function with redirect to layout, so there will be no need to insert any funcitons on particular pages

Check out this thead where I suggested an alternative solution which may be applicable in your website - with having different placeholders for different devices http://compositec1.codeplex.com/discussions/286634 this way you will have 2 sites structuraly binded. As well as having just one site to be
crawled by search engines is a SEO improvement.

I also recommend to turn-off ASP.NET cache in web.config. As you may have a bug when a user with a mobile device receives a cached page content
instead of a redirect to the mobile version of the website. To do this edit web.config

<configuration>
 <system.web>
   <caching>
    <outputCacheSettings>
        <outputCacheProfiles>
            <add name="C1Page" duration="60" varyByCustom="C1Page" varyByParam="*" enabled="false" />


....

Mar 16, 2012 at 1:14 PM
Edited Mar 16, 2012 at 1:20 PM

I would generally prefer and recommend a solution where you can keep the same url's and serve different content/layout/template based only on the headers. This way you keep the SEO ranking and don't have to build up your ranking from scratch on a new domain.

A Danish IT-magazine website is a good example of this... when you browse an article link http://www.version2.dk/artikel/peytz-co-skal-flytte-drdk-fra-microsoft-til-drupal-inden-2014-44352, the layout will depend on the actual browser

Normal Firefox

Same url, but with User-Agent set to Android

Mar 16, 2012 at 3:31 PM

Thanks for the feedback.

@napernik - Good suggestion on the meta data field.  That makes a lot of sense.  I'll work on that and update the code.

@burningice - In this case the content (words on the page) will be different on the mobile site.  I think I understand (in theory anyway) how I could apply a different template or use master pages (like described here http://compositec1.codeplex.com/discussions/283788) to change the look of the page to be more mobile friendly, but I'm not sure how I'd control having two different versions of the content on the same page.

Mar 16, 2012 at 3:41 PM

@jpk using naperniks suggestion having different PlaceHolders on the same page for Normal and Mobile content could solve different wording for different devices on the same url.

Mar 17, 2012 at 6:37 AM

Hey jpk. Great post! I love it.

you should also look up "Responsive Web Design" and "Mobile First". There's a large movement toward making sites much more responsive to different device widths.

As for different content, I'd watch the mobile space. Unless there's a really good reason, you can often display parts of your content in a different format to mobile devices using @media-queries and CSS.

I know we're planning a site on these principles. Look up @LukeW on twitter and check out http://mediaqueri.es for examples of responsive design. I totally know where you're coming from with the mobile site. We went that way for our previous site. However, mobile devices are getting more and more pervasive and more capable than desktop browsers!

Nov 5, 2012 at 1:52 AM
burningice wrote:

@jpk using naperniks suggestion having different PlaceHolders on the same page for Normal and Mobile content could solve different wording for different devices on the same url.


@burningice : In my case, this strategy would be the best.  It must depend of your type of site and it's content.  I am using v4 beta (masterpage).  Do you have an idea how to customize Composite C1 to acheive this.  Here is my reflexion but I need advises on how to implement it in CC1:

- 1 masterpage with conditionnal nested master page using a function like the IsMobileDevice. 
- 2 nested masterpages - 1 for desktops + tablets using responsive design , 1 for the mobile devices.
? Is there a way to have conditionnal nested masterpages?  I seem to be an ASP.NET specific question then a Composite C1 but maybe you have the answer.
? Do Composite C1 support nested masterpages.

 I will create Shared, Desktop and Mobile placeholders for the same page.
- Shared -> both nested masterpages
- Desktop -> Desktop nested masterpage
- Mobile -> Mobile nested master page

  My main concern is that I must hide some pages that should be only visible for desktop and tablets.  I could add a meta to my pages (mobileVisible).
? - Where do I trap this meta in Composite C1 to avoid to show the page in the menu if IsMobileDevice?

Any suggestions are welcome.

Thank you

Erik

 

Nov 5, 2012 at 7:16 AM

For the differentiating multiple .master files for a given request you can use the sample approach as the MasterPage implementation in < 4.0. It uses the PostMapRequestHandler event which hooks up to the .aspx-page of a request and assigns it a MasterPage. In here you would then add some logic for IsMobile etc.

Look at this code for inspiration https://bitbucket.org/burningice/compositec1contrib/src/bce3ed2614bb78b9f52803fded60822010c0384d/Rendering.MasterPages/Web/MasterPageModule.cs?at=default 

Nov 5, 2012 at 1:00 PM
burningice wrote:

For the differentiating multiple .master files for a given request you can use the sample approach as the MasterPage implementation in < 4.0. It uses the PostMapRequestHandler event which hooks up to the .aspx-page of a request and assigns it a MasterPage. In here you would then add some logic for IsMobile etc.

Look at this code for inspiration https://bitbucket.org/burningice/compositec1contrib/src/bce3ed2614bb78b9f52803fded60822010c0384d/Rendering.MasterPages/Web/MasterPageModule.cs?at=default 


Thank you for the link. 

Can you just guide me where to trap the event.  Should I add it to each masterpage code or I can edit and drop MasterPageModule.cs in the App_Code folder?

Erik

Nov 5, 2012 at 1:20 PM

You should add the Module-class to your App_Code and register it in your web.config.

http://msdn.microsoft.com/en-us/library/ms227673(v=vs.100).aspx

Nov 5, 2012 at 1:22 PM
burningice wrote:

You should add the Module-class to your App_Code and register it in your web.config.

http://msdn.microsoft.com/en-us/library/ms227673(v=vs.100).aspx


Thank you,

I read some posts about HTTPModule and installed v 3.2 to see how it is setup. 

Erik

Nov 6, 2012 at 2:44 PM
epaquet861 wrote:
burningice wrote:

For the differentiating multiple .master files for a given request you can use the sample approach as the MasterPage implementation in < 4.0. It uses the PostMapRequestHandler event which hooks up to the .aspx-page of a request and assigns it a MasterPage. In here you would then add some logic for IsMobile etc.

Look at this code for inspiration https://bitbucket.org/burningice/compositec1contrib/src/bce3ed2614bb78b9f52803fded60822010c0384d/Rendering.MasterPages/Web/MasterPageModule.cs?at=default 


Thank you for the link. 

Can you just guide me where to trap the event.  Should I add it to each masterpage code or I can edit and drop MasterPageModule.cs in the App_Code folder?

Erik


Hi,

I did some tests with an updated HTTPModule and I have strange behaviors.

I had this line to test :

page.Response.Write("   ===  Device type : "+ InfoDevice.UserAgentToDeviceType(httpRequest.UserAgent));

in the

private void handler_PreInit(object sender, EventArgs e)

 

 

If I open my Desktop firts, Is see Device type : Desktop.  Immediatly if I open my iPhone, I get the same device (Desktop).  But, If I open the site with my iPhone first, My Desktop show it's an iPhone.

It's look like your httpModule work at app level, not for each visitor.  I am right?

 

Erik

Nov 6, 2012 at 3:33 PM
epaquet861 wrote:
epaquet861 wrote:
burningice wrote:

For the differentiating multiple .master files for a given request you can use the sample approach as the MasterPage implementation in < 4.0. It uses the PostMapRequestHandler event which hooks up to the .aspx-page of a request and assigns it a MasterPage. In here you would then add some logic for IsMobile etc.

Look at this code for inspiration https://bitbucket.org/burningice/compositec1contrib/src/bce3ed2614bb78b9f52803fded60822010c0384d/Rendering.MasterPages/Web/MasterPageModule.cs?at=default 


Thank you for the link. 

Can you just guide me where to trap the event.  Should I add it to each masterpage code or I can edit and drop MasterPageModule.cs in the App_Code folder?

Erik


Hi,

I did some tests with an updated HTTPModule and I have strange behaviors.

I had this line to test :

page.Response.Write("   ===  Device type : "+ InfoDevice.UserAgentToDeviceType(httpRequest.UserAgent));

in the

private void handler_PreInit(object sender, EventArgs e)

 

 

If I open my Desktop firts, Is see Device type : Desktop.  Immediatly if I open my iPhone, I get the same device (Desktop).  But, If I open the site with my iPhone first, My Desktop show it's an iPhone.

It's look like your httpModule work at app level, not for each visitor.  I am right?

 

Erik


It seem to be a cache problem.  I followed the advise of Napernik about disabled the cache and it's work fine.

<configuration>
 <system.web>
   <caching>
    <outputCacheSettings>
        <outputCacheProfiles>
            <add name="C1Page" duration="60" varyByCustom="C1Page" varyByParam="*" enabled="false" />
Does anybody know if I could get some performance problems for a small web site?
Nov 6, 2012 at 4:07 PM

you shouldn't disable cache but let it vary depending on the Device Type - then asp.net will make sure to cache the mobile version of a url, and the desktop version of the same url as two distinct cache objects.

There seems to be a few article on this matter which all points to that VaryByCustom should be set to browser. This would create a conflict with the existing C1Page, but can be handled in global.asax in the GetVaryByCustomString method.

Nov 6, 2012 at 5:56 PM
burningice wrote:

you shouldn't disable cache but let it vary depending on the Device Type - then asp.net will make sure to cache the mobile version of a url, and the desktop version of the same url as two distinct cache objects.

There seems to be a few article on this matter which all points to that VaryByCustom should be set to browser. This would create a conflict with the existing C1Page, but can be handled in global.asax in the GetVaryByCustomString method.


Do you detect a problem if I cache by user-agent instead of browser?  It should create more cache files but I could use emulators / user-agent changer to test my site.

Thank you for your help.  I almost finish.

Erik