21

We all know that IE11 detection does not work with server side languages because Microsoft has removed the IE/MSIE browser indication and now is fully "Mozilla".

I also know that doing browser detection/version is risky but has served us all well in the past.

some requirements for a website are things like:

must work with certain version of firefox and above must work with certain version of chrome and above must work with certain version of safari's (some below and some newer) must work with IE >= 8

so here is the problem... IE11 indicates on my list that it is not supported. I want to support it from the web side of things on the server (ASP.NET/MVC)

it is not clear exactly how to detect this from the server side. Does anyone know how?

this is the user agent now being shown in IE 11:

"Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko"

rv:11.0 tells us its IE11 however doing a parse on that will still mean that for example, it could be chrome of a certain version that is not supported in such a requirement or even firefox.

so, what is the best way here to see if it is indeed IE 11 or higher?

I am not so sure about searching from "Trident" and onwards because I don't know if other browsers use that or not.

any direction is welcomed.

Ahmed ilyas
  • 5,722
  • 8
  • 44
  • 72
  • 4
    It seems to me that the problem exists because you are whitelisting supported browsers instead of blacklisting unsupported ones. You mention yourself how this might break: you can't whitelist future browsers because they don't exist yet. However, you *can* blacklist unsupported browsers because that's all in the past. Have you considered this? – Jon Nov 15 '13 at 11:33
  • Agreed with you Jon. This will take a bit of testing but let me see what I can do. – Ahmed ilyas Nov 15 '13 at 11:41
  • @Jon - revisiting the code and notes, seems that there are other browsers that we just do not support period - like netscape or mobile devices in general or opera or netscape.... so how can this be handled, since I don't have these browsers to check against what would be reported and to reject them? – Ahmed ilyas Nov 15 '13 at 11:43
  • Depends on how strict you need to be about disallowing unsupported browsers. If you want 100% strict then blacklisting will be a nightmare, [there are too many of them out there](http://www.useragentstring.com/pages/useragentstring.php). Perhaps whitelisting might be the way -- it depends on your exact requirements. – Jon Nov 15 '13 at 11:52
  • @Jon - agreed. we have a set defined "no go" and there aren't that many. just any netscape, any safari (except for 1), any opera are not allowed. Then we have 3 browsers (IE, firefox and chrome) that should be of a certain version or higher which are supported. Just not sure how I can proceed to invert the current code (even though the code is a few lines, its all about the min ver or higher that is supported and everything else not so much) – Ahmed ilyas Nov 15 '13 at 11:55

5 Answers5

17

Use a Regular Expression like:

Regex.IsMatch(this.Request.UserAgent, @"Trident/7.*rv:11")

Trident is the name of the rendering engine IE uses. Some other applications also use the Trident engine, as you can see in the Wikipedia article. But it shouldn't be a problem to search for Trident in the User Agent, since no other major browsers use Trident.

Only IE11 uses Trident version 7 so if you search for Trident/7 with the regex, it should find IE11.

Taylan Aydinli
  • 4,333
  • 15
  • 39
  • 33
  • Thanks. I ended up doing something like this and works (using regex). I chose not to go for the hotfix approach that @pashapash suggested because to install hotfixes on the production has to go through a long long process. – Ahmed ilyas Nov 15 '13 at 12:39
  • dotnet core changed the `UserAgent` property, get it now with `Request.Headers["User-Agent"].ToString()` – BurnsBA Sep 04 '19 at 22:00
13

To maintain compatibility with existing code, I created a custom provider so Request.Browser will return the information as expected. For example, Browser.Browser will be "IE" not "InternetExplorer", which is the new value after the hotfix is installed.

Additionally, this approach returns the actual version of IE, not version 7 when in compatibility view. Note that Browser.Type will return "IE7" when in compatibility view in case you need to detect it, or you could easily modify the custom provider to change .Type as well.

The approach is simple. Derive a class from HttpCapabilitiesDefaultProvider and set BrowserCapabilitiesProvider to an instance of your class.

In Global.asax.cs:

protected void Application_Start(Object sender, EventArgs e)
{
    ...
    HttpCapabilitiesBase.BrowserCapabilitiesProvider = new CustomerHttpCapabilitiesProvider();
    ...
}

Define your class: UPDATED TO INCLUDE MICROSOFT EDGE BROWSER

public class CustomerHttpCapabilitiesProvider : HttpCapabilitiesDefaultProvider
{
    public override HttpBrowserCapabilities GetBrowserCapabilities(HttpRequest request)
    {
        HttpBrowserCapabilities browser = base.GetBrowserCapabilities(request);

        // Correct for IE 11, which presents itself as Mozilla version 0.0
        string ua = request.UserAgent;

        // Ensure IE by checking for Trident
        // Reports the real IE version, not the compatibility view version. 
        if (!string.IsNullOrEmpty(ua))
        {
            if (ua.Contains(@"Trident"))
            {
                if (!browser.IsBrowser(@"IE"))
                {
                    browser.AddBrowser(@"ie");
                    browser.AddBrowser(@"ie6plus");
                    browser.AddBrowser(@"ie10plus");
                }

                IDictionary caps = browser.Capabilities;
                caps[@"Browser"] = @"IE";

                // Determine browser version
                bool ok = false;
                string majorVersion = null; // convertable to int
                string minorVersion = null; // convertable to double
                Match m = Regex.Match(ua, @"rv:(\d+)\.(\d+)");
                if (m.Success)
                {
                    ok = true;
                    majorVersion = m.Groups[1].Value;
                    minorVersion = m.Groups[2].Value; // typically 0
                }
                else
                {
                    m = Regex.Match(ua, @"Trident/(\d+)\.(\d+)");
                    if (m.Success)
                    {
                        int v;
                        ok = int.TryParse(m.Groups[1].Value, out v);
                        if (ok)
                        {
                            v += 4; // Trident/7 = IE 11, Trident/6 = IE 10, Trident/5 = IE 9, and Trident/4 = IE 8
                            majorVersion = v.ToString(@"d");
                            minorVersion = m.Groups[2].Value; // typically 0
                        }
                    }
                }

                if (ok)
                {
                    caps[@"MajorVersion"] = majorVersion;
                    caps[@"MinorVersion"] = minorVersion;
                    caps[@"Version"] = String.Format(@"{0}.{1}", majorVersion, minorVersion);
                }
            }
            else if (ua.Contains(@"Edge"))
            {
                if (!browser.IsBrowser(@"Edge"))
                {
                    browser.AddBrowser(@"edge");
                }

                IDictionary caps = browser.Capabilities;
                caps[@"Browser"] = @"Edge";

                // Determine browser version
                Match m = Regex.Match(ua, @"Edge/(\d+)\.(\d+)");
                if (m.Success)
                {
                    string majorVersion = m.Groups[1].Value;
                    string minorVersion = m.Groups[2].Value;
                    caps[@"MajorVersion"] = majorVersion;
                    caps[@"MinorVersion"] = minorVersion;
                    caps[@"Version"] = String.Format(@"{0}.{1}", majorVersion, minorVersion);
                }
            }
        }

        return browser;
    }
}
Doug Domeny
  • 4,410
  • 2
  • 33
  • 49
8

I solved this by using the Regex below after having a knock out system to check what browser is being used to access the site.

in this case, even if the browser "IE" is checked and returns false, I go ahead and use this regex and check to see if it is a match against the user agent:

(?:\b(MS)?IE\s+|\bTrident\/7\.0;.*\s+rv:)(\d+)

I hope this helps someone. I tested it and works fine. I also changed the rv to be 12 and upwards, and it works fine too in case if in IE12, they change rv to be 12.

Moslem Ben Dhaou
  • 6,897
  • 8
  • 62
  • 93
Ahmed ilyas
  • 5,722
  • 8
  • 44
  • 72
1
    public ActionResult Index()
    {
        var browser = this.Request.Browser;
        System.Diagnostics.Trace.WriteLine(browser.Browser); // InternetExplorer
        System.Diagnostics.Trace.WriteLine(browser.MajorVersion); // 11
        return View();
    }

Please note that you need .NET 4.5 or .NET 4.0 with http://support.microsoft.com/kb/2836939/en-us installed to correctly detect IE11.

PashaPash
  • 1,972
  • 15
  • 38
  • running .NET Framework 4.5. I do have .NET Framework 4.0 too but the site is in .NET Framework 4.5 browser.Browser reports "Mozilla" and MajorVersion is 0. – Ahmed ilyas Nov 15 '13 at 11:40
  • you need 4.5 or 4.0 with hotfix on the server side. mozilla/0 means that hotfix is not installed. try to install the hotfix. if the site is precompiled, then you will also need 4.5/hotfix on the machine used for precompilation. – PashaPash Nov 15 '13 at 12:37
  • thank you. Problem is, to install hotfixes on production is a long long process and needs to be tested for weeks on end before the green light is given. – Ahmed ilyas Nov 15 '13 at 12:39
  • 2
    The majorVersion property returns 7 from my server so you cannot rely on that. – Chris Love Nov 15 '13 at 20:27
-1

It does sound like you are whitelisting browsers, which is not a good idea. You really need to do client-side detection of capabilities instead, generally. MVC really does not know what browser it is, the Request.Browser object can give you some idea, but that is not really reliable, which is the case for IE 11. It tells me version 11 on my dev machine, but 7 on my server, which can be a catastrophic mistake.

I build Single Page Applications and have adopted a similar attitude as Google about only supporting the current and previous version of a browser only. When I detect an outdated browser I server a 'core' site that is just some basic CSS and markup, no JavaScript. It is just easier that way, makes development so much easier.

Anyway the way I detect is to test for the current versions of IE like so:

    public static bool IsModernIE() {

        return HttpContext.Current.Request.Browser.Browser == "InternetExplorer";

    }

It is an HTML helper method. So in your cshtml you can use the test. In my controller I call the individual version tests. This is ultimately a very fragile way to do it. I am basically drawing a line in the sand between modern IE (10/11) and old IE (9-). This test could be irrelevant with the next version and I have not tested against say Xbox One yet.

I have a library I use, posted on GitHub. I would call it usable Alpha right now, so take it for that and run with it if you like. I want to make the tests more externally configurable, etc. here is the URL for the repository, https://github.com/docluv/SPAHelper. I actually use it on my Blog, http://love2dev.com.

Chris Love
  • 3,740
  • 1
  • 19
  • 16
  • some say I'm whitelisting, others say Im blacklisting... well, which one should be done? We have a set of requirements and im following them. :) the requirements are that *some* browsers are ok and others not so much unless they are of a certain version. so unfortuately, gotta do it that way. Also your IsModernIE() method will fail with IE11 and up. Browser is reported as Mozilla now, not MSIE, IE or InternetExplorer. Client side detection is not sufficient for what needs to be done... – Ahmed ilyas Nov 16 '13 at 08:09
  • 1
    Without the system hotfix to patch the browser files, IE11 is detected as Mozilla. With the fix, IE11 is detected as 'InternetExplorer', as distinct from that listed for earlier IE versions ('IE'). – JT. Dec 13 '13 at 05:20
  • 1
    The only way to detect IE11+ without the patch is to (a) add your own `.browser` file in `App_Browsers` for IE11 - not recommended - or (b) look for `Trident` in the User Agent string if the browser is detected as `Mozilla`. – JT. Dec 13 '13 at 07:27