Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Configuring ASP.NET 2.0 to Properly Recognize and Identify the Google Chrome Browser

0.00/5 (No votes)
6 Jan 2012 1  
The purpose of this article is to explain how you can update your ASP.NET 2.0 site to properly recognize and identify Chrome.

Introduction

If you have developed or maintained an ASP.NET 2.0 web site, you may have discovered that ASP.NET 2.0 does not properly recognize and identify the Google Chrome browser. The purpose of this article is to explain how you can update your ASP.NET 2.0 site to properly recognize and identify Chrome.

Background

ASP.NET developers usually rely on the properties of the .NET HttpBrowserCapabilities object referenced by the HttpRequest object's Browser property. For example, to obtain the name and version of the browser, you would use code like this:

BrowserName.Text = Request.Browser.Browser;
BrowserVersion.Text = Request.Browser.Version;

or

BrowserName.Text = this.Context.Request.Browser.Browser;
BrowserVersion.Text = this.Context.Request.Browser.Version; 

The Problem

The problem is that ASP.NET 2.0 does not properly recognize Chrome. In a standard (unfixed) ASP.NET 2.0 web application, Chrome gets identified as an "AppleMAC-Safari" version 5.0. This is no surprise since ASP.NET 2.0 was released before Chrome was developed.

Many developers work around this deficiency by rolling their own code to parse the HttpRequest object's UserAgent property which is where the browser and browser version information ultimately comes from anyway. For the version of Chrome I am currently using, the User-Agent string is:

"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.63 Safari/535.7"

Seeing the User-Agent string, it is easy to understand why ASP.NET would recognize the Chrome browser as Safari since the code was released prior to the existence of Chrome.

Now you could hack your own solution to this problem but as it turns out, Microsoft developers created a fairly sophisticated system to handle browser recognition and I decided that for me, the best approach was to fix the already existing system. It turned out to be fairly simple.

The Solution

It's only a simple five step process to get ASP.NET 2.0 to properly recognize Chrome and best of all, it will not even require a code change.

Step 1: Identify your version of the .NET Framework and its directory

In my case, I am using the 64-bit framework, so my framework directory is: C:\Windows\Microsoft.NET\Framework64\v2.0.50727. If I were using the 32-bit framework, it would be: C:\Windows\Microsoft.NET\Framework\v2.0.50727. I will refer to this directory as the "framework directory" in the rest of this article.

Step 2: Copy or obtain a chrome.browser file and place it in your framework directory's CONFIG\Browsers directory

When you look in the framework directory's CONFIG\Browsers directory, you may be shocked to see all the .browser files. These .browser files are part of the sophistiated system I referred to earlier. If you examine a file, you will see it is nothing more than an XML configuration file that uses Regular Expressions to recognize the browser from the User-Agent string and to set browser capabilities. If you look carefully, you will see that it cleverly uses Regular Expressions to not only determine the browser, but to obtain the version right from the User-Agent string.

If you have .NET 4.0 installed on the web site's serving machine, you can simply copy the 4.0 framework's chrome.browser file from the 4.0 Config\Browsers directory to your framework directory's CONFIG\Browsers directory.

If you don't have .NET 4.0 installed, I have a slightly modified version of the chrome.browser file available as a download file for this article. Download and unzip it, and place it in your framework directory's CONFIG\Browsers directory.

Step 3: Decide if you want Chrome's version reported only as the major and minor version (like 16.0) or the entire version (like 16.0.912.63)

The .NET 4.0 chrome.browser file (unmodified) will only contain the major and minor version in the version number. So for the version of Chrome I am using, 16.0.912.63, it reports the version as "16.0". This isn't satisfactory for me because I want the full version number. If you use the chrome.browser file attached to this article, I have modified it to report the full version number.

Below are the relevant lines from my attached chrome.browser file. You can see that the first userAgent element has been commented out. That is the original line from the standard .NET 4.0 chrome.browser file and causes the version to be reported as only the major and minor version, "16.0". The second userAgent element is the one I have added and causes the entire version number to be reported as the version, "16.0.912.63".

<browser id="Chrome" parentID="Mozilla">
    <identification>
     <!--userAgent match="Chrome/(?'version'(?'major'\d+)(\.(?'minor'\d+)?)\w*)" /-->
        <userAgent match="Chrome/(?'version'(?'major'\d+)(?'minor'\.[.\d]*))" />
    </identification>

If you use my attached chrome.browser file and want the full version, simply leave the file as it is. If you want only the major and minor version reported for the version, uncomment the commented out userAgent element and comment out the uncommented userAgent element.

If you are using your own .NET 4.0 chrome.browser file and want only the major and minor version reported for the version, leave the file as it is. If you want the entire version number reported, comment out the existing userAgent element and add the one from the example above.

Don't worry about the comment lines negatively affecting performance because the approach I am taking here won't affect the runtime performance of your system.

Step 4: Edit the mozilla.browser file

While we now have a chrome.browser configuration file to help ASP.NET recognize the Chrome browser, unfortunately, the existing mozilla.browser file will interfere. We will need to make two modifications to it.

4.1. Make a backup of your existing mozilla.browser file

I have simply made a copy of the file in the same directory and named it mozilla.browser.bak and that doesn't seem to cause any ill effects.

4.2. Update the Gecko section

Find the browser element whose id attribute is set to "Gecko". This will begin the configuration section for recognizing the Gecko browser. Inside the browser element will be an identification element and inside it will be a userAgent element whose match attribute is set to "Gecko". Technically, this is saying if you find the string "Gecko" in the User-Agent string, this is the Gecko browser. If you examine the User-Agent string provided by Chrome and documented near the top of this article, you can see that it does indeed include the string Gecko and this will cause it to be (mis)recognized as the Gecko browser. The simple solution is to add another userAgent element below the existing one and set a nonMatch attribute to "Chrome". This will tell the system to be Gecko, the User-Agent string must include "Gecko" but not "Chrome". Here is what that section of the mozilla.browser file should look like after you add your new userAgent element:

<browser id="Gecko" parentID="Mozilla">
    <identification>
        <userAgent match="Gecko" />
        <userAgent nonMatch="Chrome" />
    </identification>

4.3. Update the Safari section

Find the browser element whose id attribute is set to "Safari". This will begin the configuration section for recognizing the Safari browser, which is the one that Chrome is currently getting (incorrectly) recognized as. Notice that farther down in that section is a capability named browser that is set to "AppleMAC-Safari". This is why Chrome is getting identified as "AppleMAC-Safari". It's all starting to make sense now, don't you think?

Inside the Safari browser element will be an identification element and inside it will be a userAgent element whose match attribute is set to "AppleWebKit/(?'webversion'\d+)". Technically, this is saying if you find the string "AppleWebKit/" in the User-Agent string, this is the Safari browser. If you examine the User-Agent string provided by Chrome and documented near the top of this article, you can see that it does indeed include the string "AppleWebKit/" and this will cause it to be (mis)recognized as the Safari browser. The simple solution is to add another userAgent element below the existing one and set a nonMatch attribute to "Chrome". This will tell the system to be Safari, the User-Agent string must include "AppleWebKit/" but not "Chrome". Here is what that section of the mozilla.browser file should look like after you add your new userAgent element:

<browser id="Safari" parentID="Gecko">
    <identification>
        <userAgent match="AppleWebKit/(?'webversion'\d+)" />
        <userAgent nonMatch="Chrome" />
    </identification>

Without any modifications to the mozilla.browser file, you will find that initially, Chrome will get recognized as Safari, which is the initial problem. If you only updated the Safari section to exclude it if the User-Agent string contains "Chrome", the browser would then get (mis)recognized as Gecko. This is why we had to update both sections of the mozilla.browser file.

Step 5: Run the aspnet_regbrowsers.exe program

Earlier I said that leaving comments in .browser files will not affect runtime performance. The reason is that these .browser configuration files are not read every time a browser makes an HTTP request. For them to become effective, we must run the aspnet_regbrowsers.exe program which will actually parse them and build an assembly that then gets linked in at runtime.

So, open a command prompt and cd to your framework directory. In it, you will find the aspnet_regbrowsers.exe program. Simply run the program and append the -i (install) parameter. This will create and install the ASP.BrowserCapsFactory.dll assembly which is the one that populates the HttpBrowserCapabilities object for you when you receive an HTTP request.

You should be aware that running the aspnet_regbrowsers.exe program will cause IIS to restart.

C:\Windows\Microsoft.NET\Framework64\v2.0.50727>aspnet_regbrowsers.exe -i
Utility to compile ASP.Net browser files.
Copyright (C) Microsoft Corporation. All rights reserved.
The browser capabilities assembly ASP.BrowserCapsFactory.dll has been successfully installed.

The results

Once you have run the aspnet_regbrowsers.exe program, you should find that Chrome gets recognized as Chrome and as the appropriate version based on your decision in Step 3. In my case, the browser is now recognized as Chrome 16.0.912.63, which is exactly what I wanted.

The risks

There are some risks to this approach. If you have an existing application that already supports Chrome, you could find this causes you trouble. Existing code, third party server controls for example, may expect Chrome to get recognized as "AppleMAC-Safari" and may examine the User-Agent string themselves to determine that the browser is Chrome. By the system now recognizing Chrome as Chrome, their code may malfunction. In my case, my application didn't already support Chrome so I didn't have this risk.

Also, when you update your system this way, it will affect all web applications using the same version of the .NET Framework (on the same server). So you might be derailing another web application while fixing yours.

The limitations and an alternative

Obviously this approach requires you to have full control of the server. In a shared server environment, you may not have this level of control. There is another approach you can take though that should solve this problem. You can add the .browser files to the App_Browsers directory in your project.

I haven't tried this approach so I don't know the details but I wanted to share this option in case you don't have control of the server, or you don't want to risk breaking other web applications on the server. If I were interested in this approach, I would want answers to the following questions:

Will the .browser files get parsed every time an HTTP request is made? How do they get used? In other words, running the aspnet_regbrowsers.exe program causes an assembly to get built once. What does just sticking the .browser files in your App_Browsers directory do instead?

Depending on the answer to the previous question, will having comments in the .browser files affect performance? If they get parsed every time a request comes in, they would. I might want to remove those comments if it would affect performance on a repeated basis, like for every HTTP request.

How will the system react to having the framework mozilla.browser file compiled into the ASP.BrowserCapsFactory.dll assembly while at the same time having a modified mozilla.browser file in your App_Browsers directory? Will your configuration properly override the one in the ASP.BrowserCapsFactory.dll assembly?

The Conclusion

There are lots of alternative approaches and hacks for determining if the browser is Chrome but since Microsoft created such an elaborate system to do so, why not use it? This approach is cleaner than most and doesn't require any code changes. Just make sure that you update all your necessary servers including those in your development, staging, testing, and production environments.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here