Ok, so a couple of days ago (or something) EPiServer released a module called Mobile Pack. It is built to make it easy for companies to get their website up and running for mobile browsers, which is pretty cool.
It uses “Visitor Groups” and a browser criterion to redirect mobile users to a mobile version of the website. A solution which is actually quite simple, but it works well, and simple well working things are great. At least it works in theory. Unfortunately, in the real world the code doesn’t work…
The problem? Well, it doesn’t redirect properly for iFruit devices. I found this out by installing the module on a site, and modifying my FireFox browsers user-agent to that of an iPhone, which looks like this
5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16
Or at least similar to it… But browsing to the site did not redirect me, which annoyed the crap out of me. And after going through every single configuration I could think of, I still couldn’t get it to work. So I assumed I had missed something, and decided to look at the code in .NET Reflector to see what was actually happening in the code. And to my surprise, it wasn’t actually me, it was the code.
There is one line of code that checks the browser user-agent to figure out if it is a mobile browser. It looks like this
public override bool IsMatch(IPrincipal principal, HttpContextBase httpContext)
This could sort of be fine, but it isn’t. First of all, comparing the user-agent to a compiled enumeration like this is a little bit too limiting for me. My WP7 device would for example not be considered a mobile device… I would have preferred a config setting in web.config or even better using the browser capabilities built in to .NET. But that isn’t the real problem…
When comparing strings like this, I recommend doing a case-insensitive check. As Contains() doesn’t support passing in a StringComparison, doing a ToLower() would at least be sweet.
In this case, this Contains() call is actually the cause of the redirect problem… As it compares the user-agent, it uses a enum that looks like this
public enum BrowserType
Caught the problem? Well, iFruits use lower-case I:s… So since the Contains() call is case-sensitive, it fails to identify i-devices as mobile devices, which is quite funny as those would be the first once I checked when building something like this…
So, how do we fix it? Well, there are two ways. Either you go to Codeplex and download the source, fix the bug, and recompile it, which is probably the easiest way. But being me, and already having the dll on disk from my NuGet “install”, I decided to fix the dll instead…
The way to do this, is to disassemble the dll to il code, fix the problem and then recompile it…
Let’s start by getting the IL code. This is done by opening ildasm.exe, which is easily done by opening the Visual Studio Command Prompt and typing ildasm followed by enter. This opens up ildasm. Then drag and drop the dll into the opened window and you get a view like this
Next, open the File menu and select Dump. In the resulting window, just press OK and select a place to save the resulting il code. This will also create a .res resource file with the same name.
This code file can then easily be opened in Notepad. After doing so, press Ctrl+F and search for “iphone”. Now change all the rows that have the incorrect capital I to use the correct spelling, and save the file and close Notepad.
Next we need to compile the il code back to a usable dll. This is done by using a tool called ilasm.exe. Unfortunately, if you just pull it up using the command prompt like we did with the ildasm, you might get into problems. The ilasm.exe application is runtime version dependent. Each version comes with its own ilasm. And starting it from the VS2010 command prompt might give you the wrong version depending on what version you are using for the EPiServer project.
So instead, we use the full path, which is
At least in my case, as my project is .NET 3.5, which means runtime version 2.0.
But we also need to pass some parameters to ilasm. Let’s use
%FrameworkDir%\v2.0.50727\ilasm MobilePakc.il /out=MobilePack.dll /res=MobilePack.res /dll
At least is you named the il file MobilePack.il…
This will now give you a new dll file that you can drop into the bin folder of your project and you are done…
This obviously works for other dll's than MobilePack, as long as they aren’t signed, as well as for other projects than EPiServer. But in this case it just happened to be an EPiServer problem…
I also want to mention that I have notified Allan who built this code about the problem, so I assume it will be fixed relatively soon…
IMPORTANT! If you have used NuGet to install the mobile pack, remember to change the reference to the new bin instead of the one in the packages folder…