I've inherited an ASP project, and I'm a PHP coder with no ASP knowledge. Sorry if this post is lengthy, I just want to give as much informations as possible.
I'm struggling with this one block of code.
Dim resultArray As String()
For Each resultitem In resultArray
' Do something with each element of the array
hash.Add(dllFunctionObj.ReturnTemplateField(i), resultitem)
i = i + 1
Next
Error:
Exception!!: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
The solution seems simple. Check if resultitem is null then either break or skip to the next element.
So I tried this:
If IsNull(resultitem) Then
Break
End If
Error:
BC30451: Name 'IsNull' is not declared.
I tried several other alternatives I found online:
IsEmpty(resultitem) - IsEmpty not declared
String.IsNullOrEmpty(resultitem) - index out of bounds error, seems to have no effect
resultitem Is Nothing - index out of bounds
Not (Len(resultitem) > 0) - index out of bounds
Len(resultitem) = 0 - index of out bounds
The only thing that seems to come close is:
If Not resultitem Then
Break
End If
Error:
Exception!!: Conversion from string "some_string_here" to type 'Long' is not valid.
If I use Next instead of Break I get this error:
If Not resultitem Then
Next
End If
Error:
BC30081: 'If' must end with a matching 'End If'.
Help!
I'm going to include the full block of code in case it is helpful
Dim isResultArray As Boolean
isResultArray = methodInf.ReturnType.IsArray()
If isResultArray Then
Dim resultArray As String()
'*** Invoke the dll function
resultArray = methodInf.Invoke(REMem, args.ToArray)
Dim i As Integer = 0
For Each resultitem In resultArray
If Not resultitem Then
Response.Write("Found null value.")
Exit For
End If
Response.Write("i: " & i & "<br />")
hash.Add(dllFunctionObj.ReturnTemplateField(i), resultitem)
i = i + 1
' i = 6 will cause Get Constituent Name to work
'If i = 6 Then
' Exit For
'End If
Next
outputArray.Add(hash)
Else
'*** could be boolean, string, long etc.
Dim result As String
'*** Invoke the dll function
result = methodInf.Invoke(REMem, args.ToArray)
hash.Add(dllFunctionObj.ReturnTemplateField(0), result)
outputArray.Add(hash)
End If
You need to make sure you're not overflowing the index of the collection you're accessing. Something like this should work:
If i < dllFunctionObj.ReturnTemplateField.Length Then
hash.Add(dllFunctionObj.ReturnTemplateField(i), resultitem)
End If
Basically, you need to wrap your call to "hash.Add" in this if block to protect against accessing a value that doesn't exist.
Granted, I don't understand the purpose of the code, so you might need to handle the "else" case. But this should stop the error.
Looks to me like the array may be defined incorrectly.
Change this:
Dim resultArray As String()
For Each resultitem In resultArray
' Do something with each element of the array
hash.Add(dllFunctionObj.ReturnTemplateField(i), resultitem)
i = i + 1
Next
To this:
Dim resultArray() As String
For Each resultitem In resultArray()
' Do something with each element of the array
hash.Add(dllFunctionObj.ReturnTemplateField(i), resultitem)
i = i + 1
Next
Additionally, you may need to define the length of the array, e.g.:
Dim resultArray(0 to 9) As String
If the length of the array is unknown, you may define it without the minimum and maximum index, but will need to use ReDim to assign the minimum and maximum indexes later. One method would be to create the array without a length, count the items that you know will be added to the array, and then use ReDim with that count as the length of the array. For example:
Dim resultArray() As String
Dim iCount as integer 'Keep track of the count with this variable.
'Enter custom counting script here...Use a loop to count the items that will be used in the array.
ReDim resultArray(0 to iCount - 1) 'Subtract one from the iCount to match the 0-based index.
If you try to call upon a index of an array that has no set length (or use an index greater/less than the size of the array), you will most likely encounter either an "Index out of range" or "Substring out of range" error.
Related
So I'm trying to put a 2D array into 2 arrays but I keep getting index out of the bounds of the array. The reason you might ask of why I'm doing this is so that I can store it in a viewstate object so I don't have to continuously retrieve my data.
The code I've been trying to use is this:
Dim testArray As String() = {}
testArray(0) = dataArray(0, 1)
and if there is a way to store a 2D array in a viewstate, let me know. Thanks!
Oh, I'm sorry, Heres the dataArray code
Private Function getDataArray() As Array
Dim x As Integer
Dim DT As DataTable
Dim TA As New DSOldOrdersTableAdapters.TA
DT = getOldOrders()
ReDim dataArray(3, DT.Rows.Count - 1)
For x = 0 To DT.Rows.Count - 1
dataArray(0, x) = DT.Rows(x).Item("SO")
dataArray(1, x) = DT.Rows(x).Item("Customer")
dataArray(2, x) = DT.Rows(x).Item("ShipBy")
Next
Return dataArray
End Function
Dim testArray As String() = {}
testArray(0) = dataArray(0, 1)
You're declaring testArray and assigning an empty array to it. Because the array is zero-length, there is no index 0, so trying to assign to testArray(0) results in an index out of bounds exception.
You need to ReDim the testArray variable, or change your assignment:
Dim testArray As String() = {}
ReDim testArray(0)
testArray(0) = dataArray(0, 1)
'or
Dim testArray As String() = {dataArray(0,1)}
Declaring
Dim testArray As String() = {}
created a string array with a dimension set to zero
So testArray is useless without a dimensioning of at least one element.
Writing
testArray(0) = dataArray(0, 1)
cause the Index Out Of bound exception
Probably you need an array of the same length of your datatable rows.
But, why all the effort to use an array in this context?.
A List(Of String) is a better solution
Dim testValues = new List(Of String)()
testValues.Add(dataArray(0,1))
In this way you don't need to know how big the testArray should be and you could use the List as an array in every place where it is required to have the array
Dim soValue = testValues(0)
or
testValues.ToArray()
The error you're having would be because, the element you're trying to refer to is not present in the Array. Index of an array starts at 0, so always try to make sure, you're refering the last element to be (maxElements - 1). Otherwise it would cause an error and you'll see this error.
Is it possible to check if a named field is within a record set?
EG id, field1, field2, field3 have been selected. Is it possible for VBScript to detect if field2 has been selected. I am also hoping this is possible without looping
Please assume I dont know, nor can see the actual SELECT. I need to detect this after the query has been executed.
This is how its done using a loop, I am also hoping this is possible without looping:
dim rs,field,foundField
sql = "SELECT * from table;"
set rs = conn.execute(sql)
For Each field in rs.Fields
if field.Name = "someFieldName" then
foundField = true
exit for
else
foundField = false
end if
next
TYIA
I use a similar function (in VB6) to the one proposed by bfavaretto... I'm curious why the OP says it doesn't work?
Public Function FieldExists(ByVal rs As Recordset, ByVal fieldName As String) As Boolean
On Error GoTo merr
FieldExists = rs.Fields(fieldName).name <> ""
Exit Function
merr:
FieldExists = False
End Function
This function works for me... and it doesn't return false negatives as far as I know. Also, it appears to be faster than executing a loop for fields that are included in the collection; for fields that are actually missing, the execution times of both methods seems to be equivalent.
EDIT
For VBScript, the above function would look like this:
Function FieldExists(ByVal rs, ByVal fieldName)
On Error Resume Next
FieldExists = rs.Fields(fieldName).name <> ""
If Err <> 0 Then FieldExists = False
Err.Clear
End Function
And the code posted in the question would look like:
dim rs,field,foundField
sql = "SELECT * from table;"
set rs = conn.execute(sql)
foundField = FieldExists(rs, "someFieldName")
I think you need the loop. Found this on MSDN (emphasis mine):
Most of the ASP built-in objects provide collections. Collections are
data structures similar to arrays that store strings, numbers, objects
and other values. Unlike arrays, collections expand and contract
automatically as items are retrieved or stored. The position of an
item will also move as the collection is modified. You can access an
item in a collection by its unique string key, by its index (position)
in the collection, or by iterating through all the items in the
collection.
In any case, you could try this (untested):
dim rs,field,foundField
sql = "SELECT * from table;"
set rs = conn.execute(sql)
if rs.Fields("someFieldName") then
' ... if this doesn't crash, it may return
' false negatives for columns containing null or 0
end if
If I place a breakpoint at the line currentrow = MyParser.ReadFields()
, currentrow still contains the values of the previous line parsed from the file. After currentrow = MyParser.ReadFields()
executes, the current file line values are stored.
Since currentrow is declared inside the While loop, shouldn't the previous currentrow value be out of scope when re-entering the While loop? Why does currentrow still retain values from the last line in the file?
Do I need to change Dim currentrow As String()
to Dim currentRow() = New String() {}? Why?
If File.Exists(filename) Then
Using MyParser As New FileIO.TextFieldParser(filename)
MyParser.TextFieldType = FileIO.FieldType.Delimited
MyParser.SetDelimiters("~")
While Not MyParser.EndOfData
Try
Dim currentrow As String()
'at this point, currentrow still contains prev values
currentrow = MyParser.ReadFields()
Catch
End Try
End While
End Using
End If
Because you have only declared the loop variable, as against this which results in a correct value of Nothing on every iteration:
Dim currentrow As String() = Nothing
or even better
Dim currentrow As String() = MyParser.ReadFields()
"Dim" by itself, without the explicit initialization, will be optimized out as redundant.
Even if you assign Nothing, it will always be reset to Nothing on every iteration. If you only declare the variable it will always contain the "wrong" old value even if you would use Console.Write or MessageBox.Show afterwards.
So always assign a default value in a loop variable to avoid side-effects.
Sidenote C# avoids this error source with the compiler warning CS0165: Use of unassigned local variable 'variablename'.
So if you would try to use that unassigned variable before it gets assigned you would not even be able to compile with C#. I don't know why VB.NET allows it.
Remember that all variables in VB have a scope of the block they're declared in, but a lifetime of the whole routine(*) (effectively from where they are declared to the end of the routine), and they're always initialised to Nothing, whatever that means for the actual type.
Dim outer As Integer
For i = 1 To 2
Dim inner As Integer
Try
Dim inner2 As Integer
Do
Dim inner3 As Integer
While True
Dim inner4 As Integer
Console.WriteLine(outer & ", " & inner & ", " & inner2 & ", " & inner3 & ", " & inner4)
outer = i
inner = i
inner2 = i
inner3 = i
inner4 = i
Exit While
End While
Loop Until True
Catch
End Try
Next
The above outputs:
0, 0, 0, 0, 0
1, 1, 1, 1, 1
(*)Anonymous routines/closures affect this. See my separate question.
I’ve written my own staticsitemapprovider which builds a dynamic site map. The problem I have is that sometimes pages will have additional parameters in the query string which I need to ignore.
Public Overrides Function FindSiteMapNode(ByVal rawUrl As String) As SiteMapNode
Dim startpos As Integer = 0
Dim endpos As Integer = 0
If rawUrl.Contains("pagetype=") Then
startpos = rawUrl.IndexOf("pagetype=")
endpos = rawUrl.IndexOf("&", startpos) + 1
If endpos >= startpos Then
'not the last param
rawUrl = rawUrl.Remove(startpos, endpos - startpos)
Else
'must be the last param
rawUrl = rawUrl.Remove(startpos)
End If
End If
Return MyBase.FindSiteMapNode(rawUrl)
End Function
I've also overridden the FindSiteMapNode function that takes in a HttpContect object. With this I simple find the URL of that request and run it though the same function above.
However with this my sitemappath (which is bound to the site map) returns nothing on every page.
In the end this turned out to be a very simple fix. All i needed to do was check to see if the the parameter was the first in the url. If it wasn't, I aslo needed to remove the ampersand - so it would be startpos - 1
Cheers
I wrote the following function that works about 95% of the time, but I need it to work 100% (obviously):
Public Shared Function getPassedVars() As String
Const keyCount As Integer = 54 ' 54 seems to be the number of parameter keys passed by default (for this web_app).
' there are more if there is a form involved (ie. from search page)
Dim oParams As String = ""
Try
With HttpContext.Current
If .Request.Params.AllKeys.Count > keyCount Then
For i As Integer = 0 To (.Request.Params.AllKeys.Count - (keyCount + 1))
oParams &= String.Format("{0}={1}{2}", .Request.Params.Keys.Item(i), .Request.Params(i), IIf(i < .Request.Params.AllKeys.Count - (keyCount + 1), ";", ""))
Next
End If
End With
Return oParams
Catch ex As Exception
Return Nothing
End Try
End Function
It scrubs the Request.Params object for passed variables, which are in the beginning of the array (the remaining ones are ASP parameters). I am pretty sure I've seen a different way to get these parameters, but I haven't been able to figure it out. Any suggestions?
EDIT
So it looks like I can use the Request.URL.Query to achieve this, I will investigate this and post back.
Here is what I came up with:
Public Shared Function getPassedVars() As String
Dim oParams As String = ""
Dim qString As String = ""
Dim oSplit As New List(Of String)
Try
With HttpContext.Current
qString = .Request.Url.Query
If qString.Length > 0 Then 'do we have any passed variables?
If qString.StartsWith("?") Then qString = qString.Remove(0, 1) 'remove leading ? from querystring if it is there
oSplit.AddRange(qString.Split("&"))
For i As Integer = 0 To oSplit.Count - 1
oParams &= String.Format("{0}{1}", oSplit.Item(i), IIf(i < oSplit.Count - 1, ";", ""))
Next
Return oParams
Else
Return Nothing
End If
End With
Catch ex As Exception
Return Nothing
End Try
End Function
So far so good.
Request.QueryString is a NameValueCollection, so the easiest way to get the "parameters" is to do the following:
foreach (String s in Request.QueryString) {
Response.Write(s + " = " + Request.QueryString[s]);
}
Where is your function located? If it's executing in the page's code behind then you definitely do not need to use the HttpContext variable.
It looks like you are trying to get values from the query string.
For example, for this URL:-
http://www.tempuri.org/mypage.aspx?param1=x¶m2=y
I assume you want retreive the values of the query string parameters param1 and param2?
If so, just use:-
Dim param1 as String = Request.QueryString("param1")
Otherwise, if these parameters are contained in a form (an HTTP POST request) then use the method which Mitchel Sellers suggests.
If you know the name you can use the following to get it by key value
Dim myParamValue as String = Request.Form("MyKeyName")
Otherwise, you can loop through the form collection, by key etc, to get the values. The key is, do you really need to be parsing all 54 items? Or are you simply looking for a few specific values?
httpcontext.Current.Request.QueryString("KeyName")
Request.Params will contain the query parameters you're after.
There's no need to parse the info from Request.URL since it's already done for you.