This is the second in a series about IE Browser Compatibility Mode. The first in the series can be found here See this post for the first in the series: https://blog.lostware.com/2019/01/15/ie-browser-compatibility-mode-part-1/

I bet you are wondering what are we talking about today. Me to. Got any ideas? No, well I suppose I will tell you all a story about the DotNet Browser Control.

The .Net Framework provides a control which can be used to host/display html content within a windows application. This Browser Control uses the IE engine for this functionality, and by default will run in IE7 mode, no matter what settings are in the browser specifically.

There are, of course, ways to control this per application. Specifically, there are a set of registry settings that can be added to ensure that web pages are rendered as expected. Rather than go through all of these I will provide links to relevant details:

https://weblog.west-wind.com/posts/2011/May/21/Web-Browser-Control-Specifying-the-IE-Version

https://blogs.msdn.microsoft.com/patricka/2015/01/12/controlling-webbrowser-control-compatibility/

On the surface it seems like everything should be easy peasy with that info. Right? Ha. Ha. Ha I say. Is anything really ever that easy? Especially when dealing with IE. That is a rhetorical question – the answer is no.

Throughout 2017 my team and I were in a mighty struggle where customers were encountering a considerable number of script errors in various parts of our application. I say that this was a struggle because first we had some difficulties in reproducing most of the issues, as we were told that all of the environments were accessing the site using IE10. Sort of – let me explain; these particular clients were accessing our site from within another application developed by a vendor partner of ours. Not only that, but the application they were using was running in a Citrix environment, adding another level of variables to the mix. And finally – we had clients with the issues, and clients that did not encounter any of these issues – yet they were all using the exact same version of our application, the partner’s application, the same version and setup of Citrix, etc.

What the hell? Right?

M going to skip straight to the end, and not go through some of the excruciating and extensive troubleshooting that we did. The long calls with clients (users and IT), our partners, gathering all of the data we could on environment settings, etc. Let’s just say it took a fair amount of time, agony, and lots of hair pulling before we finally started to zero in on the issues. (Full disclosure, I was already bald)

What was causing all these issues? Well, they all boiled down to some issue with IE7 or IE8. But why some and not the others? Well, refer back to the first article in this series for the order of precedence in how compatibility mode is determined. Some client networks had group policies set, and some were using the IE 11 Enterprise Site List to force the Browser to use IE7 emulation mode for our site.

But, hey, let’s look at some of these items and how we resolved them.

  • Incompatible markup pointers for this operation
    • This was related to a plugin for TinyMCE called nanospell. Rather than automatically adding the plugin, we checked to ensure that certain features were supported before loading the plugin.

      var nanospellSettings = {
                 external_plugins: { “nanospell”: ‘nanospell/plugin.js’ },       nanospell_server: ‘asp.net’,   nanospell_dictionary: ‘en, en_med’,
        nanospell_ignore_block_caps: true

              };
             if (window.getSelection) {
$.extend(true, settings, nanospellSettings);
}

    • Can’t move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus
      • Added feature detection:
        if (typeof window.getSelection === ‘function’ && !!window.getSelection()) {
  • Object does not support property or method trim
    • Changed the call to use the jQuery version instead, since it handled all the compatibility issues.
  • Unable to get property ‘parentNode’ of undefined or null reference
    • First we created a function to encapsulate the size details for the editor. Then we added a “try” around whether this info was added to the object based on whether feature was available:

There were more – but very soon it hit me – Man, if we keep on trying to fix these issues one by one we are going to be in a bad situation. And I’m pretty sure we would have some unhappy customers. Or worse yet – NO unhappy customers (implying they left). So, how can we ensure that all visitors to our website are getting the content rendered/executed in the correct manner? Isn’t there some sort of s9mple way that we could just fix all of these issues, and maybe ones that hadn’t been found yet? Well, sure – let me point you back to the first article in this series…again.

In order to address the issues above, we added the X-UA-Compatible ie=edge directive to the HTTP Header – since these were all related to script issues with earlier versions of IE/JavaScript engine. This resolved these issues for almost all customers. Case closed.

Or not. Because within days of the release of this fix we received reports from the same clients that a new issue had appeared. In a different area of the application there was functionality which would open content in a new window, and in that new window was a button to add content to another object. When clicking that button the JavaScript was just supposed to set a cookie, then show a dialog that said the cookie was set. But instead what the user was seeing was one of two things: either the window would close with no dialog (and the behavior did not happen as expected), or the user would receive a script error with a message like “Permission Denied”

After doing some research without really identifying the problem, I decided to check something, just on a whim. I removed the X-UA-Compatible ie=edge directive from the HTTP Header. Boom, problem vanished.

What? Why would that have led to this issue – it did not make sense.

Since this, of course, made all the earlier script issues related to IE7/IE8 return, it was not a viable solution. Neither state was acceptable to our clients, of course. We had to “swarm” on this issue a bit. And here is what we found. The HTTP header was doing what it was supposed to do. The .Net Browser Control was using IE10 “mode” to render the webpage. At which point, the way our site was working caused a security change in IE9 to cause this error.

Let’s take a quick look into what was going on:

When a user clicked on a specific link we would call window.open in JavaScript to load the webpage in a new window. During the load of this new webpage certain information was gathered in the ASP.Net webforms Page_Load event, then a redirect event would load a new page to render the appropriate content.

We had a theory that the error was somehow related to this redirect – however, before we could justify the effort needed to rewrite that functionality we needed to be able to prove it. And, better understand what was really happening.

We created a simple WinForms app, inside of which we added a custom form that contained the Browser Control and wired up the navigation to open a new instance of this form object instead of the default of opening a new window with the native browser. After doing this we were finally able to reproduce the issue. Great. Awesome. Once we saw that, we decided to debug our sample application directly, so that we could see the page object that was being rendered. And this is when we found something odd.

All of the properties on the page were null. OK, this really confirmed where the problem lie. But it brought up more questions. Why was this only happening with the x-ua tag? Why only on a new window?

Oh wait – you know what, by telling the BrowserControl to use the most recent version of the browser installed (in this case, IE10) we inadvertently enabled enhanced browser security that was introduced in IE9. Specifically, see the following: https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/hh180174(v%3dvs.85)

Here is the workflow at the time: user would search for content, in the list of results they could either select the content that they needed, or they could click on a link to view that content. The link to view the content called a JavaScript function which took the content info, opened up a new window and navigated to the URL provided. However, this didn’t load the content directly, it was more of a “way station” to get to the content. When the new webpage opened there was code that would execute in the ASP.Net Page_Load event which would do some validation of the request, attempt to find the content, then redirect to a new webpage that would THEN load the requested content.

And it was that redirect that was causing the problem. Because that redirect call somehow made the page “orphaned”, and hence IE cleared out all the object properties as mentioned above. With the page object properties null trying to set a cookie is going to understandably have some problems. In this case we get our lovely Permission Denied error. I would have expected an error about the object being null or something, but hey, there it is.

With this information it was a simple matter to get the work approved and rewrite the code so that instead of doing a redirect we just rendered the necessary objects on the first load.

So, there it is – when using the .NET Browser Control, make sure that you add the registry settings to ensure that the correct rendering engine of IE is used. There are other registry settings (referenced above) to control some of the ways that the embedded browser behaves with scripting, protocols, and so much more.

If you are developing web pages that you know are going to be accessed via an embedded browser – make sure that you are using the X-UA-Compatible ie=edge directive within the HTTP Header (you can add this as a META tag in HTML as well, but it has to be as close to the top as possible – because as soon as the browser hits the tag it will reload)

Check out some of the other resources used while dealing with these issues:

 

 

 

Leave a Reply

Discover more from Ramblings in time and measure

Subscribe now to keep reading and get access to the full archive.

Continue reading