JavaScript code working on old server, but not on new - javascript

This has been driving me crazy. I'm trying to migrate some legacy applications to a new server and I'm having a lot of problems with document.all being peppered throughout the code.
Before you say it, I know. Don't use document.all. It's there and there's nothing I can do about it...this particular problem has JavaScript within an assembly for which I do not have the source code and I don't have permission to redevelop.
My main confusion is that the current version of the application is working when I test in the same browser as my migrated version. It's a straight copy and paste job and no code has changed during the migration, but when I run the app on the new server document.all(element) always returns null.
Does IIS or newer .NET frameworks somehow handle client-side scripts differently?
I'm coming from .NET 2.0 hosted on Windows Server 2005 with IIS 6, and going to .NET 4.0 hosted on Windows Server 2012 with IIS 8.
I'm looking for ANY idea why these would be behaving differently when tested in the same browser
UPDATE:
A user control being targeted by document.all is getting encoded which is messing up the ID of the control, i.e. what should be 'elementId' is being outputted as 'elementId'
The code in the assembly is using Attributes.Add which is including single quotes. I've found a number sources suggesting a new class such as:
public class HtmlAttributeEncodingNot : System.Web.Util.HttpEncoder
{
protected override void HtmlAttributeEncode(string value, System.IO.TextWriter output)
{
output.Write(value);
}
}
being added which will allow encoding to be turned off by using <httpRuntime encoderType="HtmlAttributeEncodingNot"/> in the web.config, but I am not able to add new classes to this project

I'm going to leave the accepted answer as it is, but add this answer in case anyone else has issues with this in the future.
My circumstances changed and I was able to add a class to the project. The class in my question:
public class HtmlAttributeEncodingNot : System.Web.Util.HttpEncoder
{
protected override void HtmlAttributeEncode(string value, System.IO.TextWriter output)
{
output.Write(value);
}
}
along with using the class for the encoding in the web.config:
<httpRuntime encoderType="HtmlAttributeEncodingNot"/>
was sufficient for dealing with the single quotes in Attributes.Add being encoded to $#39;
Additionally, something to look out for with old JavaScript is the way .net renders the ClientID of controls. Using a combination of the above code, along with <xhtmlConformance mode="Legacy"/> , and clientIDMode="AutoID", I was able to render the html the same as it's 2.0 equivalent and solve my problem for the time being.

It sounds like your project is ending it's life and you just want to breath new life in to it. I think document.all is done as of IE11, isn't it - so the clock is ticking.
What I'd suggest is writing some Javascript to iterate the DOM and look for any encoded IDs - then change those back to the .NET 2 form. Run that JS at the bottom of the page (as opposed to onload) and hopefully nothing will have tried to access document.all before you 'correct' the ids.

Related

Kotlin, how can I read a dynamic website as text?

As titled, I'm trying to read the content of sites like this one, which appears to be javascript based.
I tried using plain jdk lib, then jsoup and then htmlunit, but I couldn't get anything useful out of it (I see just the source code or just the title or null):
val url = URL("https://registry.terraform.io/providers/hashicorp/tls/latest/docs/data-sources/certificate")
val connection = url.openConnection()
val scanner = Scanner(connection.getInputStream())
scanner.useDelimiter("\\Z")
val content = scanner.next()
scanner.close()
println(content)
val doc = Jsoup.connect("https://registry.terraform.io/providers/hashicorp/tls/latest/docs/data-sources/certificate").get()
println(doc.text())
WebClient().use { webClient ->
val page = webClient.getPage<HtmlPage>("https://registry.terraform.io/providers/hashicorp/tls/latest/docs/data-sources/certificate")
val pageAsText = page.asNormalizedText()
println(pageAsText)
}
WebClient(BrowserVersion.FIREFOX).use { webClient ->
val page = webClient.getPage<HtmlPage>("https://registry.terraform.io/providers/hashicorp/tls/latest/docs/data-sources/certificate")
println(page.textContent)
}
It should be something easy peasy, but I cant see what's wrong
In order for this to be possible, you need something to execute the JS that modifies the DOM.
It might be a bit overkill depending on the use case, and probably won't be possible if you're on Android, but one way to do this is to launch a headless browser separately and interact with it from your code. For instance, using Chrome Headless and the Chrome DevTools Protocol. If you're interested, I have written a Kotlin library called chrome-devtools-kotlin to interact with a Chrome browser in a type-safe way.
There might be simpler options, though. For instance maybe you can run an embedded browser instead with JBrowserDriver and still use JSoup to parse the HTML, as mentioned in this other answer.
Regarding HtmlUnit:
the page has initially no content, all you see is rendered from javascript magic on the client side using one of this spa frameworks.
It looks like there is some feature check in the beginning that figures out the js support in HtmlUnit does not have all the required features and based on this you only get a hint like "Please enable Javascript to use this application".
You can use
page.asXml()
to have a look at the content trough HtmlUnit's eyes.
You can open an HtmlUnit issue on github but i fear adding support for this will be a longer story.

Browser.ExecScript() stopped working after updating windows

I've set up a simple testbed for WatiN (ver 2.1) which reads:
var browser = new IE();
browser.GoTo("http://www.google.co.il"); // webpage doesn't matter really
browser.RunScript("alert(123)");
This works only if KB3025390 is not installed. Installing it breaks the above test with an UnAuthorizedAccessException which has HRESULT set to E_ACCESSDENIED. What gives? Is there any workaround?
Update: Using IWebBrowser2.Navigate2 along with "javascript:console.log(123)" type of scripts works however
it makes me feel uneasy using such a backchannel
the scripts run through this back-channel of .Navigate2() may only have a max length of about 2070 chars (give or take) otherwise they get forcibly truncated to this length leading to javascript errors upon attempting to run them
using .Navigate2(), even with the most trivial script, will clog the ready state of Internet Explorer for good in the sense that it will be set to READYSTATE_LOADING without any hope of getting rid of it. In simple terms this means that once you use this hack, you either have to perform every single subsequent operation in WatiN in a "dont-wait-for-webpage-to-load" fashion (GoToNoWait, ClickNoWait etc) lest your code freezes upon waiting for the browser to turn back to READYSTATE_COMPLETE (which will never come about ofcourse as already mentioned).
there appears to be a much broader issue here in the sense that I can't even access the properties of an IHtmlWindow2 object p.e. window.document throws an unauthorized exception again making it virtually impossible to transfer over to the C# world the return-values of the scripts I'm running (using Expando etc) for documents other than window.top.document (for the window.top.document window there is IWebBrowser2.Document which does the trick)
Update#2: The folks over at the selenium project have also noticed this issue:
https://code.google.com/p/selenium/issues/detail?id=8302
A bug report has been created as well:
https://connect.microsoft.com/IE/feedback/details/1062093/installation-of-kb3025390-breaks-out-of-process-javascript-execution-in-ie11
Update#3: IHTMLWindow2.setInterval and IHTMLWindow2.setTimeout also throw UnauthorizedAccess exceptions. These methods are not marked as deprecated in:
http://msdn.microsoft.com/ko-kr/library/windows/desktop/aa741505%28v=vs.85%29.aspx
yet they have wounded up suffering from the same cutbacks all the same.
Update#4: I gave the approach recommended in this post a shot:
https://stackoverflow.com/a/18546866/863651
In order to dynamically invoke the "eval" method of the IHTMLWindow2 object (or any other method really). Got the same "System.UnauthorizedAccessException" as above. So no joy here either.
Microsoft recommends using "eval" over "execscript" however after the above experiment I suspect that they are refering to accessing "eval" only from within the browser.
As far as I can tell thus far, when it comes to the full-fledged IE11+ using "eval" out-of-process (via COM) appears to have been completely prohibited along with any other function-invocation of the window object, the only exception being the back-channel of the .Navigate2() mentioned above.
It turns out Microsoft eventually backpedaled on its decision to kill off .execScript at COM-level. Just install the latest updates for Windows including kb3025390: One of the updates for IE that came after kb3025390 brings back .execScript functionality at COM-level
Note, however, that .execScript is not accessible through IE's javascript anymore. In that context it's gone for good.
fyi: this one is also not working
ieInstance.Document.Script.<methodNameString>(<commaSeperatedParameterString>)
try this worked for me at some places but not all places
ieObject.Navigate "javascript:<methodNameString>(<commaSeperatedParameterString>)", Null, "_parent"
or
ieObject.Navigate2 "javascript:"<methodNameString>(<commaSeperatedParameterString>)", Null, "_parent"
now trying to find out solution using eval
I have found a way around the problem of an update installing automatically. You can just create a simple batch file with following content.
{code}
#echo off
wusa /uninstall /kb:3025390/quiet /norestart
END
{code}
Then go to task scheduler, create a new task for this batch file to run every one hour or day as per your requirements. Add it as a system task so it runs in the background and does not affect the running automations.

How to manage ASP.NET parameters and Javascript keys

So here is my scenario.
Im using ASP.NET MVC 3 along with HTML, CSS, JavaScript/JQuery to make a web application.
Im using Visual Studio 2010
We have already released the product (its in 1.0), however now that we are in "maintenance" mode for the project, I have a feeling that as the project has new features added, that it will be harder to maintain the set of constants between both the C# (ASP.NET MVC) and the JavaScript.
For example, in the JavaScript I would create a $.post and have it link to the MVC url Controller/Action and then I would pass in parameters { key1: value1, key2: value2}
The issue is that if the C# parameter names change or if the position of parameters in the signature change, I will only know at run-time that the JavaScript needs to be updated (im assuming that im a programmer that doesn't know the architecture well enough to do this before run time).
So my question is, how do you manage the JavaScript side more easily so that i can stay "in-sync" with changes made on the C# side. Can the compiler do this for me in some way, or is there a plug-in that can help me out?
Thanks.
Your question asks about syncing C# constants and JavaScript constants, but then also talks about parameter names and positions.
The positions of parameters matter less in the MVC world than the names, and I've not found a good way of keep those in sync short of extensive unit and integration testing. You are doing those tests, right? ;)
As far as actual constants and enums, I've taken to using T4 templates to generate both a .cs and a (namespaced) .js file for the constants/enums I need (in my case, out of a database, but could just as easily be anything else).
I can't think of any easy way, but here is something that may help. when I usually develop some website , first of all I try to write as least possible javascript code in views and have them all in .js file, this way you can be sure that you can reuse many codes and since all codes are pure javascript there won't be any problem you mentioned. I also keep the record of all actions with their controller and area name in database and use them for manage permissions and security issues. for your problem you can add all this method to database and later with a piece of code check if this method exist anymore.
adding to DB:(in base controller, so you don't need to do anything manually )
protected override void OnActionExecuting(ActionExecutingContext filterContext)
{
var area = filterContext.RouteData.DataTokens["area"];
string areaName = area != null ? area.ToString() : "";
var controllerName = filterContext.ActionDescriptor.ControllerDescriptor.ControllerName;
string actionName = filterContext.ActionDescriptor.ActionName;
//Add to DB
base.OnActionExecuting(filterContext);
}
check if that exist:
bool exist = false;
try
{
HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create("http://www.example.com/image.jpg");
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
exist = response.StatusCode == HttpStatusCode.OK;
}
}
catch
{
}
Your best option is integration tests. You'll be able to test exactly the actions your users would do. Seleno is a good option (it wraps Selenium) for writing integration tests.
It's worth doing. If you have good integration test coverage you'll run into fewer bugs in production.

How can I manage MSI session state within Javascript Custom Actions?

I have an ISAPI DLL, an add-on to IIS. I build the installer for it using WIX 3.0.
In the installer project, I have a number of custom actions implemented in Javascript. One of them, run at the initiation of the install, stops any IIS websites that are running. Another starts the IIS websites at the end of the install.
This stuff works, the CA's get invoked at the right times and under the right conditions. but the logic is naive. It stops all websites in the beginning (even if they are already stopped) and starts all websites at the end (even if they were previously stopped). This is obviously wrong.
What I'd like to do is keep track in the session of which websites required a stop at the beginning, and then, at the end, only try to restart those websites. Getting the state of a website is easy using the ServerState property on the CIM object. The question I have is, how should I store this information in the MSI session?
It's easy to stuff a single piece of information into a session Property, but what's the best way to store a set of N pieces of information, one for each website? In some cases there can be 1 website, in some cases, 51 websites.
I suppose I could use each distinct website name to create a distinct property name. Just not sure that is the best, most-efficient, most efficacious way to do things. Also, is it legal to use slashes in the name of an MSI Session property? (the website names will have slashes in them)
Suggestions?
You might want to check out:
VBScript (and Jscript) MSI CustomActions suck
C++ or C# is a much better choice. If your application already has dependencies on the framework then adding dependencies in your installer is a good logical choice. WiX has Deployment Tools Foundation ( DTF ) that has a custom action pattern that feels a lot jscript. You could then create a dictionary of websites and their run state and serialize it out to a single property. On the back side you could reconsitute that collection and then act upon it.
Not to mention the debugging story is MUCH better in DTF.
There's a simple solution. I was having a brain cramp.
All of the items I needed to store were strings - actually the names of websites that had been stopped during the installation. I just used the Javascript String.join method to create a single string, and the stuffed that into the session variable. Like this:
Session.Property("CA_STOPPEDSITES") = sitesThatWereStopped.join(",");
Then to retrieve that information later in another custom action, I do
var stoppedSites = Session.Property("CA_STOPPEDSITES");
if (stoppedSites != null) {
var sitesToStart = stoppedSites.split(",");
....
Simple, easy.

Getting URL of executing JavaScript file (IE6-7 problem mostly)

Hey all, I've been trying to throw together a generic function that retrieves the absolute URL of an executing JavaScript file on a web page:
http://gist.github.com/433486
Basically you get to call something like this:
getScriptName(function(url) {
console.log(url);
// http://www.example.com/myExternalJsFile.js
});
inside an external JavaScript file on a page and can then do something with it (like find the <script> tag that loaded it for example).
It works great in almost all the browsers I've tested (Firefox, Chrome, Safari, Opera v10 at least, and IE 8).
It seems to fail, however, in IE 6 and 7. The callback function gets executed, but the retrieved name is the URL to the main HTML page, not the JavaScript file. Continuing with the example, getScriptName invokes the callback with the parameter: http://www.example.com/index.html
So all I'm really asking is if there's some other way of getting the URL of the current JavaScript file (which could be IE 6 and 7 specific hackery)? Thanks in advance!
EDIT: Also, this won't work in every case, so please don't recommend it:
var scripts = document.getElementsByTagName("script");
return scripts[scripts.length-1].src;
I'd like it to work in the case of dynamically created script tags (possibly not placed last in the page), aka lazy-loading.
A lot of this depends on what you have access to. If, as it appears, you are trying to do this entirely within the JS code, I do not believe that you are able to do it, for some of the reasons shown above. You could get 90% of the way maybe, but not be definitive.
If you are working in a dotnet environment ( which is the only one I know ), I would suggest the use of a module that would intercept all JS requests and add into them the request location, or something of that nature.
I think you need to address this from the server side, not the client side. I do not think you will have a definitive answer form the client side. I think you will also struggle to get an answer from the server side, but you might be more successfull.
Sorry, I suspect you might struggle with this. IE earlier than version 8 typically gives error messages from javascript errors of the form:
line: 342
char: 3
error: expected identifier, string or number
code: 0
url: http://example.com/path/to/resource
where the url is the window.location.href, rather than the URL of the external Javascript resource that contains the problem. I suggest that IE gives the unhelpful URL value since the script URL isn't available to IE at that point, and neither is it available to any Javascript you might write to try to display it.
I would love to be able to link to IE8 release notes which say this bug / feature has been fixed, hence the reason I created this as community wiki. My MSDN foo is pretty weak!

Categories

Resources