locked
Mastering Browser Definition Files RRS feed

  • Question

  • User2325333 posted

    Mastering Browser Definition Files

    First, I apologize if this is long, but I hope some of you find it useful.

    Recently, I decided that I wanted to expand the number of browsers supported by my web site. With the new browser detection features in ASP.NET 2.0, this seemed like a simple idea. It was obvious from the beginning that I needed to create my own browser definition file, but I quickly learned that this was going to be an exercise in frustration.

    As probably some of you may have already done, I went and created my own browser definition file only to find out that it wasn’t working. I figured I had written something wrong, so I spent countless hours reading the documentation from Microsoft, yet my browser definition file did not work.

    In the process of figuring things out, I stumbled across many websites, including http://www.asp.net where several users discuss playing with browser definition files. However, almost everyone tries to make things work by changing the default browser definition files distributed with .NET. My concern with this method is that it is not an acceptable method, at least for me. The reason is that my web site is hosted by a third party vendor, and they won’t let me make changes to the default files. Furthermore, Microsoft also warns against this practice as they state that those files can be modified during security patches and upgrades. So what do we do? You probably have tried placing your “.browser” file in the App_Browsers folder, and it didn’t work. Well, the key to making your custom browser file is to understand how they work. Furthermore, I will show you how it is even possible to change the results returned by the default browser definition files without modifying them!

    NOTE: In this article, I do not explain the syntax of the .browser files. Use the Microsoft documentation for that. Furthermore, I assume you know where to copy them and how to properly name the files. So make sure you understand some of the “bare” basics about the .browser files. If you have played with them in frustration, then this article should make sense… or so I hope.

    NOTE TO DEVELOPERS: One more caveat. There is a small bug (or so it seems) that prevents new or modified .browser files in the App_Browser folder from being detected and compiled. Read the section at the end of this article for further information. This small bug can create a lot of frustration during the development process; and as result, it may make you believe that my examples don’t work.

    So… Who’s Your Daddy?

    One of the most important concepts to understand about browser definition files is that Microsoft created a very elegant parent-child solution. The whole concept of browser definition files hang on the fact that each browser definition has a parent from which they inherit their most basic notion of identity (kind of like real life… creepy!). This parent-child relationship is so important that the “Default” browser definition file itself has a special element named “defaultbrowser”. This “defaultbrowser” element in essence is the root of the parent-child tree, and all of the other browser definition files are inherited directly or indirectly from this big daddy.

    Now, having said that, you have probably figured out by now that you can use the “parentID” element to define from whom you are inheriting your browser definition. However, I have seen many people try to make “Default” or “Mozilla” their parents only to find out that it doesn’t work! This is why I asked “who is your daddy?”. Bottom line is that you shouldn’t inherit from definitions like “Default” or “Mozilla” because they are too high in the chain. They are not your parents, they are more like you great, great, great, grandparents. You must find who your real parent is.

    Why is it important to find the real parent? Well…contrary to popular belief, each child definition has the power to override settings inherited from their parent, so it is important to understand that the last browser definition file wins. This means that your “.browser” files in the App_Browsers folder have the power to override ALL the settings from the default files.

    If you don’t believe me, I’ll have to prove it to you. So here is my trick…

    To find what parent you wish to inherit from, first determine what is the ID returned by the default browser definition files. To do so, you could spend all day trying to read the XML files, or you could write a simple ASPX file to tell you. I have included a simple ASPX file below that does just that. Name this file ID.ASPX and copy it to your ASP.NET server to use it.

    <!-- ****** CUT BELOW THIS LINE *************************************** -->
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    <html>
    <head>
        <title> Browser Info </title>
    </head>
    <script language="C#" runat="server">
        System.Web.HttpBrowserCapabilities browser;

        void Page_Load(Object sender, EventArgs e) {   
            browser = Request.Browser;
        }
    </script>
    <body>
        <b>User Agent:</b> <%= Request.UserAgent %><br/>
        <b>Browser:</b> <%= browser.Browser %><br/>
        <b>Id:</b> <%= browser.Id %><br/>
    </body>
    </html><?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p>

    <!-- ****** CUT ABOVE THIS LINE *************************************** --><o:p></o:p>

    Figure 1 - ID.ASPX File Used to Determine Browser ID<o:p></o:p>

    <o:p> </o:p>

    A very important concept to understand is that the ID returned using only the default files is what defines your browser in the current browser definition tree. The ID returned is the very last match found for your browser. So if you are going to create a custom browser definition, you MUST make the ID returned by our ID.ASPX app the parent ID in your new file!

    <o:p> </o:p>

    To explain this in action, I am going to describe this process by creating a browser definition file to identify the browser of the Sony PlayStation Portable (PSP). (HINT: This is what got me started in all of this!)

    Browser Definition File for the Sony PlayStation Portable

    If we run the ID.APSX file shown above with the browser in the Sony PlayStation Portable, you’ll see that it returns the following results.

    User Agent: Mozilla/4.0 (PSP (PlayStation Portable); 2.00)
    Browser: Netscape
    Id: netscape4<o:p></o:p>

    Well, this makes sense. Since the User Agent string starts with “Mozilla/4.0”, netscape4 is the best matching definition we can find. So there it is! We have found our parent. The ID returned is “netscape4”, so that means that we need to inherit our browser definition from “netscape4”. Since we are no longer lost children, we can now go define ourselves and tell the world who we really are!

    <o:p> </o:p>

    So to create a browser definition file for the PSP browser, we need to include the following information in our file. You can name the file “psp.browser”.

    <!-- ****** CUT BELOW THIS LINE *************************************** -->
    <browsers>
        <!-- Sample "Mozilla/4.0 (PSP (PlayStation Portable); 2.00)" -->
        <browser id="PSP" parentID="Netscape4">
            <identification>
            <userAgent match="PlayStation.Portable\);.(?'version'(?'major'\d+)(?'minor'\.\d+))\w*" />
            </identification>

            <capabilities>
                <capability name="browser" value="PSP" />
            </capabilities>
        </browser>
    </browsers>
    <!-- ****** CUT ABOVE THIS LINE *************************************** --><o:p></o:p>

    Figure 2 – Basic Browser Definition File for the Sony PSP

    <o:p> </o:p>

    The code is simple. We state that our parentID is “Netscape4” (note that letter case doesn’t seem to matter). We defined a unique ID; this is very important. We don’t want to look like anyone else. And finally, we define a useful User Agent match. You’ll need to review regular expressions to understand what is going on here.

    <o:p> </o:p>

    Now if we simply copy our new PSP browser definition file to the App_Browsers folder, running our ID.ASPX, we get the following results. (Note: If you have a PSP, you can try this!)

    User Agent: Mozilla/4.0 (PSP (PlayStation Portable); 2.00)
    Browser: PSP
    Id: psp<o:p></o:p>

    In case you are curious, below is my complete PSP.browser file. The capabilities were researched to the best of my knowledge. You can simply cut-n-paste this file to your App_Browsers folder, and you’ll be identifying Sony PlayStation Portables all day long!

    <!-- ****** CUT BELOW THIS LINE *************************************** -->
    <browsers>
        <!-- Sample "Mozilla/4.0 (PSP (PlayStation Portable); 2.00)" -->
        <browser id="PSP" parentID="Netscape4">
            <identification>
            <userAgent match="PlayStation.Portable\);.(?'version'(?'major'\d+)(?'minor'\.\d+))\w*" />
            </identification>

            <capture>
            </capture>

            <capabilities>
                <capability name="browser"                        value="PSP" />
                <capability name="majorVersion"                   value="${major}" />
                <capability name="minorVersion"                   value="${minor}" />
                <capability name="version"                        value="${version}" />
                <capability name="type"                           value="PSP${major}" />
                <capability name="platform" value="PlayStation Portable" />
                <capability name="mobileDeviceManufacturer"       value="Sony" />
                <capability name="mobileDeviceModel" value="PlayStation Portable" />

                <capability name="activeXControls"                value="false" />
                <capability name="backgroundSounds"               value="false" />
                <capability name="beta"                           value="false" />
                <capability name="canSendMail"                    value="false" />
                <capability name="cookies"                        value="true" />
                <capability name="defaultScreenCharactersHeight"  value="40" />
                <capability name="defaultScreenCharactersWidth"   value="80" />
                <capability name="defaultScreenPixelsHeight"      value="272" />
                <capability name="defaultScreenPixelsWidth"       value="480" />
                <capability name="ecmascriptversion"              value="1.5" />
                <capability name="frames"                         value="false" />
                <capability name="inputType" value="virtualKeyboard" />
                <capability name="isColor"                        value="true" />
                <capability name="isMobileDevice"                 value="true" />
                <capability name="javaapplets"                    value="false" />
                <capability name="maximumRenderedPageSize"        value="300000" />
                <capability name="requiresOutputOptimization"     value="false" />
                <capability name="screenBitDepth"                 value="32" />
                <capability name="supportsXmlHttp"                value="false" />
                <capability name="vBScript"                       value="false" />

            </capabilities>
        </browser>
    </browsers>
    <!-- ****** CUT ABOVE THIS LINE *************************************** --><o:p></o:p>

    Figure 3 – Complete Browser Definition File for the Sony PSP

    Overriding the Standard Results

    Now, I told you that we could even override any result returned by the default browser definition files. Well, here is the proof. Let’s take the Firefox browser for example. The default browser definition files do a good job of identifying Firebox in both Windows and Linux, but we want to have fun with it, so here we go.

    If we run our ID.ASPX from Firefox, you’ll get something like the results shown below.

    User Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8) Gecko/20051111 Firefox/1.5
    Browser: Firefox
    Id: mozillafirefox<o:p></o:p>

    So just for fun, cut-n-paste the file below to a file named “test.browser” and copy it to the App_Browsers folder. Note that our parentID is “MozillaFireFox”.

    <!-- ****** CUT BELOW THIS LINE *************************************** -->
    <browsers>
        <browser id="MozillaFirefoxNew" parentID="MozillaFirefox">
            <identification>
                <userAgent match="Firefox" />
            </identification>

            <capabilities>
                <capability name="browser"  value="WackyBrowser" />
            </capabilities>
        </browser>
    </browsers>
    <!-- ****** CUT ABOVE THIS LINE *************************************** --><o:p></o:p>

    Figure 4 – Sample Browser Definition File to Override Default Firefox Detection

    <o:p> </o:p>

    If we run our ID ASPX file again, this time we’ll get the following results.

    User Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8) Gecko/20051111 Firefox/1.5
    Browser:
    WackyBrowser
    Id:
    mozillafirefoxnew<o:p></o:p>

    Pretty neat, huh? Like I said, “Who is you daddy?” As you can see from above, we are not just limited to overriding the “browser” capability; we can override any defined capability or even add new ones! The sky is the limit as long as you know the proper parentID to inherit from.

    <o:p> </o:p>

    If you don’t have Firefox to try this, just apply the same principles we have been talking about. Find the current browser ID returned for your browser, and replace “MozillaFireFox” for your browser ID in our “test.browser” file. Once ASP.NET compiles our new browser files, your browser will claim that it’s our new “WackyBrowser”. (Did I misspell “whacky”? Oh, well!)

    Bugs

    Some of you may have been trying this stuff and still saying, “It doesn’t work!”  Well, the problem is that there is a bug in ASP.NET related to compiling new browser files. Although Microsoft states that “.browser” files in the App_Browsers folder are detected and compiled on the fly, I have found out that this is not always the case.

    From my own tests, below are some quirky behavior patterns I discovered that should help you during development.

    ·         The first .browser file created in the App_Browsers folder is detected and compiled with no problems.

    ·         Any additional .browsers files are not detected UNTIL a change is detected on the first file.

    So, what this means is that if you create additional .browser files, you need to trigger a change on the first .browser file. You can do this by simply saving the first .browser file with your text editor without making any real modifications. This changes the modified date of the file which seems to be enough for ASP.NET to recompile all the .browser files. After creating several .browser files, I have noticed that if I see that changes to one of the files don’t take effect, then simply modifying the date of any of the other files seems to do the trick.

    Conclusion

    As you can see, the scheme created by Microsoft for the browser definition files is very powerful and extremely customizable. Unfortunately, Microsoft has not done a good job of properly documenting this versatile feature. I have shown in this article how tap into the parent-child relationship of the browser definition files to successfully create your own browser definition files. This is very important if you need to host your site with a vendor that won’t let you modify the default browser definition files.

    I have also given you a fully working browser definition file for the Sony PlayStation Portable (PSP), and shown that it is possible to override any setting for any browser properly detected by the default browser definition files distributed with .NET.

    I hope this information is useful to some of you.

    Enjoy!

    -F.P.

     

    Monday, January 23, 2006 2:40 AM

All replies

  • User-630802948 posted

    Very insightful, however, then what? This topic has been clear as mud. How are they actually used to load different CSS stylesheets for various browsers when using Themes for example?

    Monday, December 8, 2008 8:21 PM