简体   繁体   中英

Internet explorer 11 detection on server side

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.

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.

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;
    }
}

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.

    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.

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM