15

We have an application which uses Request.Browser.MajorVersion as part of a cache key. We have a challenge to determine which cache key was used for a set of historic requests. To do this we're analysing IIS logs so need to determine what the value would have been for ASP.NET's Request.Browser.MajorVersion for each request. Is it possible to derive this from the user agent string alone?

UPDATE

I originally assumed the value of Request.Browser.MajorVersion would be the version taken direct from the user agent string. However, in a debug session to confirm this theory I see this:

Debug session screenshot

I would have expected Request.Browser.MajorVersion to be 61, not 44. Can anyone provide any insight into why these values differ, and how I might be able to confidently tell what the value of Request.Browser.MajorVersion would be for a given user agent string?

UPDATE 2

I have discovered that ASP.NET uses a set of templates to build the HttpBrowserCapabilities object set as Request.Browser. These are available here:

%SystemRoot%\Microsoft.NET\Framework[version]\Config\Browsers

Looking at the templates, they all use regex to parse the user agent string (I've pasted the contents of chrome.browser below), which suggests that Request.Browser.MajorVersion should correspond with the value in the user agent string. So still no idea why my local application is returning 44 as that value.

<browsers>
    <!-- Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US) AppleWebKit/530.1 (KHTML, like Gecko) Chrome/2.0.168.0 Safari/530.1 -->
    <browser id="Chrome" parentID="WebKit">
        <identification>
            <userAgent match="Chrome/(?'version'(?'major'\d+)(\.(?'minor'\d+)?)\w*)" />
        </identification>

        <capabilities>
          <capability name="browser"                         value="Chrome" />
          <capability name="majorversion"                    value="${major}" />
          <capability name="minorversion"                    value="${minor}" />
          <capability name="type"                            value="Chrome${major}" />
          <capability name="version"                         value="${version}" />
          <capability name="ecmascriptversion"               value="3.0" />
          <capability name="javascript"                      value="true" />
          <capability name="javascriptversion"               value="1.7" />
          <capability name="w3cdomversion"                   value="1.0" />
          <capability name="supportsAccesskeyAttribute"      value="true" />
          <capability name="tagwriter"                       value="System.Web.UI.HtmlTextWriter" />
          <capability name="cookies"                         value="true" />
          <capability name="frames"                          value="true" />
          <capability name="javaapplets"                     value="true" />
          <capability name="supportsCallback"                value="true" />
          <capability name="supportsDivNoWrap"               value="false" />
          <capability name="supportsFileUpload"              value="true" />
          <capability name="supportsMaintainScrollPositionOnPostback" value="true" />
          <capability name="supportsMultilineTextBoxDisplay" value="true" />
          <capability name="supportsXmlHttp"                 value="true" />
          <capability name="tables"                          value="true" />
        </capabilities>
    </browser>
</browsers>

UPDATE 3

I have finally got to the bottom of this. It turns out that the application I was debugging was using a third-party service called 51 Degrees which intercepts the request and applies its own parsing of the request header, in this case using a database installed locally on the application server. This database had become out of date and was therefore producing strange results for nmore recent browser versions. My details in Update 2 above are valid for vanilla ASP.NET applications, but this does explain why my results were diverging from a vanilla test environment. Thanks to everyone who spared the time to help me investigate this.

Tom Troughton
  • 3,941
  • 2
  • 37
  • 77
  • 3
    Does https://github.com/ua-parser/uap-csharp help? – mjwills Oct 12 '17 at 11:02
  • Thank you. I hadn't come across this. I just tried though and it doesn't seem to return the sme major version as the .NET framework. For example, passing in user agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36" returns 61 as the major version. But the same user agent in ASP.NET has Request.Browser.MajorVersion == 44. I have no idea where .NET is getting that 44 from... – Tom Troughton Oct 12 '17 at 11:25
  • Is there a particular reason you want 44 when 61 is clearly the right answer? – mjwills Oct 12 '17 at 11:26
  • The application I'm investigating uses Request.Browser.MajorVersion as part of a cache key. I'm trying to understand for a set of requests logged in IIS which cache key was used. But I totally take your point, no idea why .NET returns 44. – Tom Troughton Oct 12 '17 at 11:27
  • Why is this question being marked down? It's a clear programming question about ASP.NET framework? Would appreciate it if someone would explain. – Tom Troughton Oct 12 '17 at 12:09
  • 1
    The short answer is, "NO", at least not 100% reliably, because some browsers will let you play with the useragent string. But you might be able to get close enough to meet your needs. – Joel Coehoorn Oct 26 '17 at 14:20
  • Thank you, but I'm still keen to get a specific answer as to a) _why_ the ASP.NET framework doesn't return a major version derived directly from the user agent string, and b) is there any way to derive what major version number would be returned by ASP.NET for a given user agent string. – Tom Troughton Oct 26 '17 at 14:26
  • And what .NET version your application runs under? – Evk Oct 26 '17 at 15:55
  • @Evk It's version 4.5.2 – Tom Troughton Oct 26 '17 at 16:00
  • Never trust user input including userAgent. It can be faked so easy. – Alex Kudryashev Oct 28 '17 at 05:05
  • OK, I get that. But it's not relevant to my question I'm afraid. Regardless of whether a user agent is faked or not I want to know how ASP.NET derives the major version. – Tom Troughton Oct 28 '17 at 07:11
  • 1
    I cannot reproduce your result. In my debug session Chrome 61.0 returns `Request.Browser.MajorVersion` == 61, Firefox 56.0 returns 56, and Edge (a little supprisingly) returns `Request.Browser.Browser` == `Chrome` and `Request.Browser.MajorVersion` == 52. All these values exist in `UserAgent` strings. – Alex Kudryashev Oct 28 '17 at 18:32
  • That's very interesting. Particularly if your results differ from mine. Would suggest any code that relies on Request.Browser could be unreliable. Thank you for taking the time, Alex. I'm going to make some time to build a more compete test framework capable of stimulating a wider range of user agent contexts, see if I can find a pattern. Will report back. Very surprised I can't get any definitive answers. – Tom Troughton Oct 28 '17 at 19:37
  • Try to send `POST` request (to avoid caching). – Alex Kudryashev Oct 30 '17 at 02:51
  • "...that relies on Request.Browser could be unreliable". Open Developer Console in Chrome and click on `Toggle Device Toolbar`. Depending on your selection "Browser" will be `iPhone`, `iPad`, and whatever you want. – Alex Kudryashev Oct 30 '17 at 02:58
  • Also use `console.log(navigator.userAgent);` in that Developer Console to see what the browser sends. – Alex Kudryashev Oct 30 '17 at 03:10
  • Finally solved this. See my Update 3. Thanks all for your help. – Tom Troughton Oct 30 '17 at 16:11
  • Why are you using browser version as a part of a cache key? – Leonid Vasilev Nov 02 '17 at 10:05
  • I agree this is pretty weird, but it's the default behavior of the CMS which wraps this application, so not my design choice. – Tom Troughton Nov 02 '17 at 10:07

1 Answers1

1

Very challenging.

This page will tell you your agent string:

http://www.useragentstring.com/

This page will show you agent string for most browsers http://www.useragentstring.com/pages/useragentstring.php

Some browsers have a major/minor version in the agent string. Some do not. The format various between browser and even between browser version, so even if you know the major version exists in the agent string, parsing it out can still be specific to each browser/version.

If you really need to do this, you're better off finding a library that is kept up to date and well maintained.

Jeremy
  • 44,950
  • 68
  • 206
  • 332