How to avoid IndexOutOfRangeException indexing DataReader columns? - asp.net

I am having a little trouble with an 'IndexOutOfRangeException'. I think it is because when the code tries to get the DateModified col from the database it sometimes contains NULLS (the users haven't always updated the page since they created it).
Here is my code;
s = ("select datemodified, maintainedby, email, hitcount from updates where id = #footid")
Dim x As New SqlCommand(s, c)
x.Parameters.Add("#footid", SqlDbType.Int)
x.Parameters("#footid").Value = footid
c.Open()
Dim r As SqlDataReader = x.ExecuteReader
While r.Read
If r.HasRows Then
datemodified = (r("DateModified"))
maintainedby = (r("maintainedby"))
email = (r("email"))
hitcount = (r("hitcount"))
End If
End While
c.Close()
I thought (after a bit of msdn) that adding;
If r.HasRows Then
End If
Would solve the problem, but so far after adding I am still getting the same old IndexOutOfRangeException
(ps, I have tried datemodified as string / datetime)

Try r.IsDBNull(columnIndex).

Does changing
datemodified = (r("DateModified"))
to
datemodified = (r("datemodified"))
work?

I have tried to recreate you issue by passing in nulls, empty sets. I can't recreate it in the sample of code you provided. Would you mind posting more code, maye even the whole page? Is there a line number that the error happens on? I would like to dig in further.

Related

Replace the value in asp.net

I want to replace the numeric value in drpFPortofCall.SelectedValue.ToString.
For example, given the string AEJEA~12060 I want the result to be AEJEA. Given the string INNSA~12430 I want the result to be INNSA only. How can I do this?
I tried the following but wasn't able to get through.
Dim frmport As String = drpFPortofCall.SelectedValue.ToString
frmport = frmport.Replace("~", "")
Easy and Simple
Using IndexOf you will replace the rest
Dim frmport As String = drpFPortofCall.SelectedValue.ToString()
Dim value as String = frmport.Substring(0, frmport.IndexOf("~"))
You can use regex to extract everything until the "~".
Here is an example. And a fiddle.
Dim foo = "AEJEA~12060"
Dim match = Regex.Match(foo,".+?(?=~)")
Dim x = match.Value
Console.WriteLine("x = " & x)
Edit: you will need this import:
Imports System.Text.RegularExpressions
First of all, I'm pretty sure drpFPortofCall.SelectedValue is already a string (What you have might not be a ListControl directly, but it almost certainly inherits this property from it). That is, further calling .ToString() from there is silly at best and wasteful at worst.
Moving on from there, it seems like you want everything up to the ~. One option looks like this:
Dim frmport As String = drpFPortofCall.SelectedValue.Split("~"c)(0)
But that might be slower. With a little more code we could do it like this, which might be very slightly faster:
Dim endIndex As Integer = drpFPortofCall.SelectedValue.IndexOf("~"c)
Dim frmPort As String = drpFPortofCall.SelectedValue.SubString(0, endIndex)
... but you won't notice the difference unless you need to run this on 10s of thousands of inputs.
Finally, the two samples we have are strikingly similar in structure, down to the number of characters in each spot. If you can be sure that all of your data follows this format exactly, we can do even better:
Dim frmPort As String = drpFPortofCall.SelectedValue.SubString(0, 5)

How to check fields for null

I know how to do this, but am wondering about best practices...
I go get a row of data from a table. Some of these fields can be NULL. I am currently using an if statement for each field and if it is NOT NULL, populate text boxes or labels as appropriate.
This seems cumbersome to me, but I couldn't think of a better method to check for nulls and act accordingly.
Does this make sense? Is there a better way?
Since vb.net 14 best way is to use ?
With Visual Basic 14 you can elegantly handle the possibility of a
null like this, using the new ?. operator:
Console.WriteLine("{0} ({1})",
customer.Name,
customer.Address?.Country)
Link to vb.net article.
Link to c# article.
If you are using a SqlDataReader to process a SqlCommand, then you can inspect the SqlDataReader.IsDBNull property. Here's a real world example:
Try
Using con = New SqlConnection(dbConnectString)
Using cmd = New SqlCommand("usp_GetValue", con)
cmd.Parameters.Add("#nvcKey", SqlDbType.VarChar).Size = key.Length
cmd.Parameters("#nvcKey").Value = key
con.Open()
Using reader As SqlDataReader = cmd.ExecuteReader()
If reader.Read() Then
If Not reader.IsDBNull(1) Then ExpriryDateUTC = reader.GetDateTime(1)
AllowMemoryCache = reader.GetBoolean(2)
If reader.IsDBNull(0) Then
value = Nothing
Return False
Else
value = DeserializeDataContractOjectFromXML(Of T)(reader.GetString(0))
Return True
End If
Else
Return False
End If
End Using
End Using
End Using
Catch ex As Exception
Return False
End Try

Update database row where there is a certain value

I need to update a row where there exists a certain value. The ExecuteNonQuery returns a 0 meaning the database is not being updated. When stepping through in debug, the update is hit and contains the correct values, however no updates are being done.
string verifySql = #"UPDATE UserInfo SET Verified='#Verified'
WHERE UserID='#UserID'";
using (var con = newSqlConnection(
ConfigurationManager.ConnectionStrings["UserInfoDB"].ConnectionString))
using (var cmd = new SqlCommand(verifySql, con))
{
con.Open();
cmd.Parameters.AddWithValue("#Verified", "Verified " + DateTime.Now);
cmd.Parameters.AddWithValue("#UserID", user.UserId);
Response.Write(cmd.ExecuteNonQuery());
con.Close();
}
Lose the single quotes around the parameter names in your sql statement. You don't need them, and they're making your code interpret your parameter placesholders as simple string literals.
Then remove the con.Close() line. You don't need that either; it's covered by the using block.
Finally, you might also consider changing your verified column to a simple DateTime type, rather than trying to store that data as text.

Eliminate Portion of String in VB.NET

Lets say I have a variable: varEmail. It contains a variable equal to the user's email address, so it might contain a value like:
"myemail#emailserver.com"
Now, lets say I want to get just a portion of the email address, e.g. strip off the domain, like so:
"myemail"
How can I accomplish this in VB.NET with string manipulation? I know this must be simple...maybe it is just early in the morning...
The first one gives the email name; the second gives the domain name.
dim varEmail as string="myemail#emailserver.com"
MsgBox(varEmail.Substring(0, varEmail.IndexOf("#")))
MsgBox(varEmail.Substring(varEmail.IndexOf("#") + 1))
If you know you are always dealing with valid email addresses, the easiest way might be as so:
varEmail = varEmail.Split("#"c)(0)
For the fun of it, here is a more old school approach that still works in .Net (and like Matt's answer, this assumes you know this is a valid E-mail Address)...
strResult = Mid(varEmail, 1, (InStr(varEmail, "#") - 1))
If you aren't sure you have a valid e-mail do this in a try catch (it will throw an exception if the e-mail is not valid)...
Dim objMail As New System.Net.Mail.MailAddress(varEmail)
strResult = objMail.User
You can use Split method. For example:
Dim MyString As String = "myemail#emailserver.com"
Dim MyString2() As String
Dim MyString3 As String
MyString2 = Split(MyString, "#", -1, CompareMethod.Binary)
MyString3 = MyString2(0)
Now MyString3 = myemail
Here is the solution for your problem:
Dim value, result as string
value="myemail#emailserver.com"
result = value.Substring(0, value.IndexOf('#')+1)
I hope this will help you out.

Simple query with ADO and Classic ASP

I want to simply retrieve a single record from a database in a classic ASP page. The code below basically works, but there are a couple problems I need help solving:
1) I want to see if a record was returned or not. result is not Nothing, so the redirect at the bottom is never performed. contact.RecordCount always returns -1, so I apparently can't use that either. Oddly, trying to access RecordCount outside the function throws an "Object doesn't support this property or method: 'RecordCount'" error.
2) I've read about disconnected queries and have seen examples where the connection and command are closed and/or set to Nothing at the end of the function. Is there a definitive best practice on what I should do?
3) Will using a parameterized query fully protect me from SQL injection, or do I need to manually remove dangerous words and characters?
function GetContactByUsername(username)
Dim conn, command, param, contact
set conn = server.CreateObject("adodb.connection")
conn.Open Application("DatabaseConnectionString")
Set command = Server.CreateObject("ADODB.COMMAND")
set command.ActiveConnection = conn
command.CommandType = adCmdText
command.CommandText = "Select * from MY_DATABASE.dbo.Contact where Username = ?"
Set param = command.CreateParameter ("Username", adVarWChar, adParamInput, 50)
param.value = username
command.Parameters.Append param
Set contact = Server.CreateObject("ADODB.RECORDSET")
contact.Open command
Response.Write contact.RecordCount '' always -1
set GetContactByPurlCode = contact
end function
dim result
result = GetContactByUsername(Request.QueryString("username"))
if result is Nothing then '' never true
Response.Redirect "/notfound.asp"
end if
FirstName = Trim(result("FirstName"))
LastName = Trim(result("LastName "))
1) To check for a lack of records, use rs.EOF, not "Is Nothing." The RecordSet object is always an object. It's just that sometimes it doesn't have any rows.
If you want to use RecordCount but are getting -1, then switch to a client-side cursor (adUseClient).
2) No definitive best-practice here, but I've personally always closed the Connection and Command, and have not had much in the way of performance problems. Connection objects are particularly precious, so close them as early as possible on high volume pages.
3) Yes, parameterizing your variable is perfect, unless you are calling a stored procedure that constructs a dynamic query.
By the way, you should avoid "SELECT *" as that will cause you to return more data than needed and is a maintenance problem waiting to happen.

Resources