Iterating through IHtmlElementCollection - asp.net

I have a VB webapplication that needs to read information from an excisting webpage on the internet. Therefore I use the mshtml library. I read the html into an ihtmldocument3 interface. After that I iterate through an ihtmlelementcollection and everything worked fine in Visual Studio 2010 Debugger. At least, the first time. When I debug the code for the second time, after iterating a few elements, the next elements return nothing and I get an exception. (When I break into the code the ihtmlelementcollection shows 0 items.) When I rename all the variables, it runs properly, but again, only the first time.
Here's the code I use to debug. I have outlined the actual code because that responds into an exception (null reference). Do I need to manually release a collection or something or am I doing something stupid?
'global variable
Private tables as IHTMLElementCollection
...........................................
Dim tableChildren As IHTMLElementCollection = tables(3).children
Dim trElements As IHTMLElementCollection = tableChildren.item(0).getElementsByTagName("tr")
Dim intCount As Integer 'just for debugging purposes
For Each element As IHTMLElement In trElements
intCount += 1 'for debugging purposes
Debug.Print(intCount.ToString & vbNewLine & element.innerHTML)
'strLine1 = element.children(0).innerText
'strLine2 = element.children(1).innerText
'and so on...
Next

I assume that by this point you've already resolved the problem one way or another, but I thought I'd suggest the HtmlAgilityPack. It has the advantage of being written to support just this type of scenario, and (as far as I know) is a native .NET library rather than being COM-based. It might be a better fit for your situation.

Related

Is web automation with Openoffice BASIC even possible?

I'm trying to do some simple webscraping in OpenOffice (I usually work in Excel but I'm trying to port something over for a coworker that doesn't have Excel). However, when I try to run something very similar to this, it keeps giving me this BASIC runtime error 1.
Here's the relevant code, I'm not sure what I'm supposed to do to make this work.
Sub Macro1
Dim explorer As Object
Set explorer = CreateObject("InternetExplorer.Application")
explorer.Visible = True
explorer.navigate("www.yahoo.com")
Const READYSTATE_COMPLETE As Long = 4
Do While explorer.Busy Or explorer.readyState <> READYSTATE_COMPLETE
Loop
dim page as object
set page = explorer.Document
dim mailButton as object
set mailButton = page.GetElementByID("ybar-navigation-item-mail") 'this is the line the error occurs on
mailButton.Click
End Sub
Do you know that you can save script in vbs file (you have to delete types in variables declarations) and run it directly by double click without using office application? I recommend you to use this way.

How to use caching?

Basically, I retrieved a dataset and I want to cache it in the server memory for one month. So I don't need to call the query again and again when running the page within this month.
I did some research and think http://msdn.microsoft.com/en-us/library/system.web.caching.cacheitemremovedcallback%28v=vs.110%29.aspx is the way to do the cache, basically i modified the sub codes to fit into my application
Public Sub RemovedCallback(k As String, v As Object, r As CacheItemRemovedReason)
itemRemoved = True
reason = r
End Sub
Function AddItemToCache(cacheKey as String, ds as Dataset)
itemRemoved = False
onRemove = New CacheItemRemovedCallback(AddressOf Me.RemovedCallback)
If (IsNothing(Cache(cacheKey))) Then
Cache.Add(cacheKey, ds, Nothing, DateTime.Now.AddMonths(1), TimeSpan.Zero, CacheItemPriority.High, onRemove)
End If
End Function
There are quite a few errors in this piece of code. One of the error is for Cache(cacheKey) says that " Cache is a type and cannot be used for expression"? where did i do wrong?
Sounds like you're using IIS cache. First of all, if this is your route - if you have an assemblies that may use cache (when available), you need to create Caching assembly in which you check for HTTPcontext. If it is null - you are running outside of IIS and caching will not be available.
A good alternative is to download Enterprise Library Caching blocks if you working with framework up to 3.5. If you use FW4.0+ you use system.runtime.caching. This way cache will be available always. There is also AppFaric and some third party cache implementations but this is probably outside the scope for you.
For your error, it sounds like your identifier Cache [your code is not showing how you assign it] is actually a type. That is if you did this
If Integer Is Nothing....
What you need is to use is syntax
System.Web.Caching.Cache.Add...
Now, this is instance. So, what you can do is
Dim c as Cache = System.Web.Caching.Cache
c.Add(....

QueryString not accepting & - Needs to

I need to be able to handle an HTML encoded ampersand in my .Net code.
So the Url is
http://myite.com/index.aspx?language=en&Refresh=true
There is no way of changing this as it has been generated by something else so this is out of my control.
How can I read the Refresh parameter?
I have tried
HttpUtility.UrlDecode(Request.QueryString("Refresh"))
but my Request.QueryString("Refresh") is actually empty, so this is pointless, as is Uri.EscapeDataString.
This can't be the first time this has happened, but I'm struggling to find a solution, as most people would say use UrlEncoding, but as I said, the Url is out of my control.
& in your query string should be %26.
Since you can't correct the url.
You can read the refresh value as:
Request.QueryString("amp;Refresh");
Note that the developer of the service you are using may correct this in future.
It would be good to be ready for that already.
var refresh = Request.QueryString("amp;Refresh");
if(String.IsNullOrEmpty(refresh))
refresh = Request.QueryString("Refresh");
nunespascal answer pretty much solves your problem. There are some alternate methods.
If its guaranteed that your Refresh parameter is the second key in the QueryStringCollection then you can use Request.QueryString(1)
Another method is to do a Contains on the QueryStringCollection.
If Request.QueryString IsNot Nothing AndAlso Request.QueryString.AllKeys.Count() > 0 Then
Dim refreshKey = Request.QueryString.AllKeys.FirstOrDefault(Function(nv) nv.Contains("Refresh"))
If refreshKey IsNot Nothing Then
Dim refreshValue = Request.QueryString(refreshKey)
End If
End If

Check if an Object exists in VBScript

I'm maintaining a Classic ASP app written in VB Script by an outside company long, long ago.
I have an array of imagefile paths, like so:
dim banners, arrKeys, i
set banners=CreateObject("Scripting.Dictionary")
banners.Add "banner1.jpg", "http://www.somelink.com"
banners.Add "banner2.jpg", "http://www.somelink.com"
banners.Add "banner3.jpg", "http://www.somelink.com"
This will exist ONLY on pages that have banner ads. There is some standard code that iterates through this list in an include file (common to all pages).
If Not banners Is Nothing then
' then loop through the Dictionary and make a list of image links
End if
The problem is that if banners is not instantiated on the page (it's not on all pages), I get a Can't find object error
What's the proper way to check if an object exists in VB Script?
#Atømix: Replace
If Not banners Is Nothing then
and use
If IsObject(banners) Then
Your other code you can then place into an include file and use it at the top of your pages to avoid unnecessary duplication.
#Cheran S: I tested my snippets above with Option Explicit on/off and didn't encounter errors for either version, regardless of whether Dim banners was there or not. :-)
IsObject could work, but IsEmpty might be a better option - it is specifically intended to check if a variable exists or has been initialised.
To summarize:
IsEmpty(var) will test if a variable exists (without Object Explicit), or is initialised
IsNull(var) will test if a variable has been assigned to Null
var Is Nothing will test if a variable has been Set to Nothing, but will throw an error if you try it on something that isn't an object
IsObject(var) will test if a variable is an object (and will apparently still return False if var is Empty).
If a variable is declared, but not initialized, its value will be Empty, which you can check for with the IsEmpty() function:
Dim banners
If IsEmpty(banners) Then
Response.Write "Yes"
Else
Response.Write "No"
End If
' Should result in "Yes" being written
banners will only be equal to Nothing if you explicitly assign it that value with Set banners = Nothing.
You will have problems, though, with this technique if you have Option Explicit turned on (which is the recommendation, but isn't always the case). In that case, if banners hasn't been Dimed and you try to test IsEmpty(banners), you will get a runtime error. If you don't have Option Explicit on, you shouldn't have any problems.
edit: I just saw this related question and answer which might help, too.
Somewhat related is IsMissing() to test if an optional parameter was passed, in this case an object, like this:
Sub FooBar(Optional oDoc As Object)
'if parameter is missing then simulate it
If IsMissing(oDoc) Then Dim oDoc as Object: oDoc = something
...
You need to have at least dim banners on every page.
Don't you have a head.asp or something included on every page?
Neither of IsEmpty, Is Object, IsNull work with the "Option Explicit" Setting, as stealthyninja above has misleadingly answered.
The single way i know is to 'hack' the 'Option Explicit' with the 'On Error Resume Next' setting, as Tristan Havelick nicely does it here:
Is there any way to check to see if a VBScript function is defined?

is it possible to issue dynamic include in asp-classic?

I mean, like php'h include...
something like
my_file_to_be_included = "include_me.asp"
-- >
for what I've seen so far, there are a couple of alternatives, but every one of them has some sort of shortcoming...
what I'm trying to figure out is how to make a flexible template system... without having to statically include the whole thing in a single file with a loooooong case statement...
here there are a couple of links
a solution using FileSysmemObject, just lets you include static pages
idem
yet another one
same thing from adobe
this approach uses Server.Execute
but it has some shortcomings I'd like to avoid... seems like (haven't tried yet) Server.Execute code runs in another context, so you can't use it to load a functions your are planning to use in the caller code... nasty...
same thing
I think this one is the same
this looks promising!!!
I'm not sure about it (couldn't test it yet) but it seems like this one dinamycally handles the page to a SSDI component...
any idea???
No you can't do a dyanmic include, period.
Your best shot at this is a server.execute and passing whatever state it needs via a Session variable:-
Session("callParams") = BuildMyParams() 'Creates some sort of string
Server.Execute(my_file_to_be_included)
Session.Contents.Remove("callParams")
Improved version (v2.0):
<%
' **** Dynamic ASP include v.2.0
function fixInclude(content)
out=""
if instr(content,"#include ")>0 then
response.write "Error: include directive not permitted!"
response.end
end if
content=replace(content,"<"&"%=","<"&"%response.write ")
pos1=instr(content,"<%")
pos2=instr(content,"%"& ">")
if pos1>0 then
before= mid(content,1,pos1-1)
before=replace(before,"""","""""")
before=replace(before,vbcrlf,""""&vbcrlf&"response.write vbcrlf&""")
before=vbcrlf & "response.write """ & before & """" &vbcrlf
middle= mid(content,pos1+2,(pos2-pos1-2))
after=mid(content,pos2+2,len(content))
out=before & middle & fixInclude(after)
else
content=replace(content,"""","""""")
content=replace(content,vbcrlf,""""&vbcrlf&"response.write vbcrlf&""")
out=vbcrlf & "response.write """ & content &""""
end if
fixInclude=out
end function
Function getMappedFileAsString(byVal strFilename)
Dim fso,td
Set fso = Server.CreateObject("Scripting.FilesystemObject")
Set ts = fso.OpenTextFile(Server.MapPath(strFilename), 1)
getMappedFileAsString = ts.ReadAll
ts.close
Set ts = nothing
Set fso = Nothing
End Function
execute (fixInclude(getMappedFileAsString("included.asp")))
%>
Sure you can do REAL classic asp dynamic includes. I wrote this a while back and it has opened up Classic ASP for me in a whole new way. It will do exactly what you are after, even though people seem to think it isn't possible!
Any problems just let me know.
I'm a bit rusty on classic ASP, but I'm pretty sure you can use the Server.Execute method to read in another asp page, and then carry on executing the calling page. 15Seconds had some basic stuff about it - it takes me back ...
I am building a web site where it would have been convenient to be able to use dynamic includes. The site is all ajax (no page reloads at all) and while the pure-data JSON-returning calls didn't need it, all the different html content for each different application sub-part (window/pane/area/form etc) seems best to me to be in different files.
My initial idea was to have the ajax call be back to the "central hub" main file (that kicks the application off in the first place), which would then know which sub-file to include. Simply including all the files was not workable after I realized that each call for some possibly tiny piece would have to parse all the ASP code for the entire site! And using the Execute method was not good, both in terms of speed and maintenance.
I solved the problem by making the supposed "child" pages the main pages, and including the "central hub" file in each one. Basically, it's a javascript round-trip include.
This is less costly than it seems since the whole idea of a web page is that the server responds to client requests for "the next page" all the time. The content that is being requested is defined in scope by the page being called.
The only drawback to this is that the "web pieces" of the application have to live partly split apart: most of their content in a real named .asp file, but enough of their structure and relationship defined in the main .asp file (so that, for example, a menu item in one web piece knows the name to use to call or load another web piece and how that loading should be done). In a way, though, this is still an advantage over a traditional site where each page has to know how to load every other page. Now, I can do stuff like "load this part (whether it's a whole page or otherwise) the way it wants to be loaded".
I also set it up so each part can have its own javascript and css (if only that part needs those things). Then, those files are included dynamically through javascript only the first time that part is loaded. Then if the part is loaded repeatedly it won't incur an extra overhead.
Just as an additional note. I was getting weird ASCII characters at the top of the pages that were using dynamic includes so I found that using an ADODB.Stream object to read the include file eliminated this issue.
So my updated code for the getMappedFileAsString function is as follows
Function getMappedFileAsString(byVal strFilename)
Dim fso
Set fso = CreateObject("ADODB.Stream")
fso.CharSet = "utf-8"
fso.Open
fso.LoadFromFile(Server.MapPath(strFilename))
getMappedFileAsString = fso.ReadText()
'Response.write(getMappedFileAsString)
'Response.End
Set fso = Nothing
End Function

Resources