Assigning value to item within an arraylist by index - asp.net

I have this VB.NET ArrayList object which is working quite well. I have built it like this. It's the first one I have used.
Public Class MyObj
Private _str1 As String
Private _str2 As String
Public Property Str1() As String
Get
Return _str1
End Get
Set(ByVal value As String)
_str1 = value
End Set
End Property
Public Property Str2() As String
Get
Return _str2
End Get
Set(ByVal value As String)
_str2 = value
End Set
End Property
Public Sub New(ByRef pStr1 As String)
_str1 = pStr1
End Sub
End Class
Then I initiialise it doing this...
Dim MyObj1 As ArrayList = New ArrayList()
MyObj1.Add(New MyObj("myTestString"))
So this is all working later on. So I pack up the arraylist and store it in a class level variable. Then in a different method I grab my arraylist. I then want to assign a value to _str2. Does anyone have advice on how I would go about this. I keep trying to know avail. This is the sort of thing I mean.
For i = 0 To MyObj1.Items.Count - 1
MyObj1.Item(i)("Str2") = "tesstring2"
Next

As Tim wrote, you will be better off using a List instead of the old ArrayList.
To set it up and then access the property Str2 of the instances of MyObj:
Dim myList As New List(Of MyObj)
myList.Add(New MyObj("Hello"))
For i = 0 To myList.Count - 1
myList(i).Str2 = "World"
Next
Notice how it is .Str2, not ("Str2").

Related

Routine to compare new and old string values, maintain old data if nothing new

I have a Form which allows users to enter new Data for a record. In order to maintain Data Integrity, I copy all the pre-existing Data (if Any) into the Record and overwrite only those fields which the user has added new Data to. This new Record is saved to the database and the old Record Deleted.
I'm merely trying to find the most efficient way of going through each field to :
determine if there is Current Data to Maintain
New Data to Overwrite
I'll need to write the same type of Check for String, Decimal, Date and Integer (all nullable)
Here's my string check
Private Function CreateRecordforSubmission() As Business.Casualty
Dim c As Business.Casualty = Casualty
c.alias = CheckStringValues(c.alias, txtAlias.Text.Trim())
Return c
End Function
Private Function CheckStringValues(OldValue As String, newValue As String) As String
If Not OldValue Is Nothing AndAlso Not String.IsNullOrEmpty(newValue) Then
'<-- There is NEW DATA
If Not String.IsNullOrEmpty(newValue) Then
Return newValue
Else
'<-- No NEW DATA, check of there is CURRENT DATA to maintain
If Not OldValue Is Nothing Then
Return OldValue
Else
Return String.Empty
End If
End If
Else
'<-- NO CURRENT DATA AND no changes have been made
Return String.Empty
End If
End Function
Check out how CSLA does it. Each property in your object could take care of that comparison, if the setter detect a change or new value, you can update your variable and mark your object as modified.
Public Property Alias As String
Get
Return _alias
End Get
Set(ByVal value As String)
If Not String.IsNullOrEmpty(value) AndAlso _alias <> value Then
_alias = value
_objectWasModified = True
End If
End Set
End Property
The If statement could be in the base class, or a helper class.
If you want to have a generic function for other type, here's an example. This assume that you are using nullable values.
Public Property Number As Integer?
Get
Return _number
End Get
Set(ByVal value As Integer?)
If Not IsNullOrSame(Of Integer)(_number, value)Then
_number= value
_objectWasModified = True
End If
End Set
End Property
Public Function IsNullOrSame(Of T As Structure)(ByVal oldValue As Nullable(Of T), ByVal newValue As Nullable(Of T))
If newValue.HasValue Then
If Not oldValue.HasValue OrElse Not oldValue.Value.Equals(newValue.Value) Then
Return False
End If
End If
Return True
End Function

Problems implementing a recursive find extension method

I am attempting to implement a recursive extension method in VB.net that will find all objects with a certain property set so I can call it like so...
Dim camp As New CampaignStructure 'Populated with a full structure of course
Dim lstFoundItems As List(Of CategoryStructure) = camp.Categories.FindRecursive((Function(c) c.Found = False), 3)
My VB.Net classess and modules currently look like this
Imports System.Runtime.CompilerServices
Namespace MyStructure
Public Class CategoryStructure
Public Property CategoryID As Integer = Nothing
Public Property Name As String
Public Property Rank As Integer
Public Property Found As Boolean = False
Public Property Children As New List(Of CategoryStructure)
End Class
Public Class CampaignStructure
Public Property CampaignID As String = Nothing
Public Property Categories As List(Of CategoryStructure)
End Class
Public Module ControlExtensions
<Extension()> _
Public Function FindRecursive(cs As List(Of CategoryStructure), predicate As Func(Of CategoryStructure, Boolean), depthLimit As Integer) As List(Of CategoryStructure)
If cs Is Nothing OrElse cs.Count = 0 Then
Return New List(Of CategoryStructure)()
End If
If depthLimit = 0 Then
Return cs.OfType(Of CategoryStructure)().Where(predicate).ToList()
Else
'**ERROR IS THROWN HERE**
Return cs.OfType(Of CategoryStructure)().Where(predicate).ToList().Union(cs.Cast(Of CategoryStructure).Select(Of List(Of CategoryStructure))(Function(c) c.Children.FindRecursive(predicate, depthLimit - 1)).ToList())
End If
End Function
End Module
End Namespace
However I'm having casting problems when I'm unioning the recursive result with the current list at the point in the code marked. I can see why that's happening, just have no idea how to resolve it. Please do not send me C# examples as there is no 'yield' alternative in VB.net
That's because both sides of UNION have different signatures.
cs.OfType(Of CategoryStructure)().Where(predicate).ToList()
This returns List(Of CategoryStructure).
cs.Cast(Of CategoryStructure).Select(Of List(Of CategoryStructure))(Function(c) c.Children.FindRecursive(predicate, depthLimit - 1)).ToList()
This one returns List(Of List(Of CategoryStructure))
I think what you're looking for is:
Return cs.OfType(Of CategoryStructure)().Where(predicate).Union(cs.Cast(Of CategoryStructure).SelectMany(Function(c) c.Children.FindRecursive(predicate, depthLimit - 1))).ToList()
SelectMany returns flattened collection typed as IEnumerable(Of CategoryStructure).

Can i use a single session variable to store all the field values

I have 9 pages with 10 fields in each page. Can i use a single session variable to store all the field(textbox,drop downlist,radiobuttons) values of 9 pages? If so could you give me small example inorder to proceed. Im kind of stuck.
Could you? Yes. Should you? Most likely not - though I can't say for sure without understanding what problem you are intending to solve.
Update with one sample solution
OK, I'm going to assume you want to store the values from the controls and not the controls themselves. If so, the easiest solution is stuff them in using some meaningful token to separate them. Like:
Session("MyControlValueList") = "name='txt1',value='hello'|name='txt2', value'world'"
To retrieve you would split them into a string array:
myArray = Session("MyControlValueList").Split("|")
And then iterate through to find the control/value you want.
So strictly speaking that's an answer. I still question whether it is the best answer for your particular scenario. Unfortunately I can't judge that until you provide more information.
Create a custom class with all the fields you want to save, then populate an instance of that and save that instance as a session variable.
I have something similar, but not identical - I'm saving various shipping address fields for an order, and I'm allowing the admins to update the order, either the shipping information or the order line items. Since that information is kept on separate tables, I store the shipping information in a session variable, and then compare it to what's on the form when they hit the "Update" button. If nothing has changed, I skip the update routine on the SQL Server database.
The easiest way for me to do this was to create a "OrderInfo" class. I saved the shipping information to this class, then saved that class to a session variable. Here's the code showing the class -
Public Class OrderInfo
Private v_shipname As String
Private v_add1 As String
Private v_add2 As String
Private v_city As String
Private v_state As String
Private v_zipcd As String
Private v_dateneeded As Date
Private v_billingmeth As Integer
Public Property ShipName() As String
Get
Return v_shipname
End Get
Set(value As String)
v_shipname = value
End Set
End Property
Public Property Add1() As String
Get
Return v_add1
End Get
Set(value As String)
v_add1 = value
End Set
End Property
Public Property Add2() As String
Get
Return v_add2
End Get
Set(value As String)
v_add2 = value
End Set
End Property
Public Property City() As String
Get
Return v_city
End Get
Set(value As String)
v_city = value
End Set
End Property
Public Property State() As String
Get
Return v_state
End Get
Set(value As String)
v_state = value
End Set
End Property
Public Property ZipCd() As String
Get
Return v_zipcd
End Get
Set(value As String)
v_zipcd = value
End Set
End Property
Public Property DateNeeded() As Date
Get
Return v_dateneeded
End Get
Set(value As Date)
v_dateneeded = value
End Set
End Property
Public Property BillingMeth() As Integer
Get
Return v_billingmeth
End Get
Set(value As Integer)
v_billingmeth = value
End Set
End Property
End Class
Here's the code for when I tested the concept to see if I could store a custom class in a session variable. This routine gets the order record, populates the fields in an instance of the custom class, and on the web form, as well. I save that instance to a session variable, then I initialize another new instance of that custom class, load the session variable to it. I then display the field values from the "retrieved" custom class, and what showed on the label matched what it should be -
Protected Sub LoadOrderInfo(ByVal ordID As Integer)
Dim connSQL As New SqlConnection
connSQL.ConnectionString = ConfigurationManager.ConnectionStrings("sqlConnectionString").ToString
Dim strProcName As String = "uspGetOrderInfoGeneral"
Dim cmd As New SqlCommand(strProcName, connSQL)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.AddWithValue("OrderID", ordID)
If connSQL.State <> ConnectionState.Open Then
cmd.Connection.Open()
End If
Dim drOrderInfo As SqlDataReader
drOrderInfo = cmd.ExecuteReader
If drOrderInfo.Read Then
Dim orgOrder As New OrderInfo
orgOrder.ShipName = drOrderInfo("shipName")
orgOrder.Add1 = drOrderInfo("ShipAdd1")
orgOrder.Add2 = drOrderInfo("ShipAdd2")
orgOrder.City = drOrderInfo("ShipCity")
orgOrder.State = drOrderInfo("ShipState")
orgOrder.ZipCd = drOrderInfo("ShipZip")
orgOrder.DateNeeded = drOrderInfo("DateNeeded")
orgOrder.BillingMeth = drOrderInfo("BillingMethodID")
If Session.Item("orgOrder") Is Nothing Then
Session.Add("orgOrder", orgOrder)
Else
Session.Item("orgOrder") = orgOrder
End If
' I could just as easily populate the form from the class instance here
txtShipName.Text = drOrderInfo("shipName")
txtAdd1.Text = drOrderInfo("ShipAdd1")
txtAdd2.Text = drOrderInfo("ShipAdd2")
txtCity.Text = drOrderInfo("ShipCity")
txtState.Text = drOrderInfo("ShipState")
txtZipCd.Text = drOrderInfo("ShipZip")
selDate.Value = drOrderInfo("DateNeeded")
ddlBillMeth.SelectedValue = drOrderInfo("BillingMethodID")
End If
cmd.Connection.Close()
Dim retOrder As New OrderInfo
retOrder = Session.Item("orgOrder")
lblWelcomeMssg.Text = retOrder.ShipName & ", " & retOrder.Add1 & ", " & retOrder.City & ", " & retOrder.DateNeeded.ToShortDateString & ", " & retOrder.BillingMeth.ToString
End Sub
This might not be practical or desirable, given the number of fields you are trying to hold onto that way, but I'm not here to judge, so this is one possibility. I've worked with other projects where you create a table, and save that table as a session variable, so whatever structure you put into an object is retained if you save that object as a session variable.

How can I set the value of this cookie property from code behind?

I would like to do this: Dim str As String = class.isGuest("yes") but it won't work.
Public Property IsGuest(ByVal guestStatus As String) As String
Get
Dim guestCookie As New HttpCookie("g")
For Each key As String In Context.Response.Cookies.Keys
If key = MYACCOUNT_SESSION_COOKIE_NAME Then
guestCookie = Context.Response.Cookies.Item(MYACCOUNT_SESSION_COOKIE_NAME)
Exit For
End If
Next
guestCookie.Value = guestStatus
Response.Cookies.Add(guestCookie)
Return guestCookie.Value.ToString
End Get
Set(ByVal value As String)
Dim guestCookie As New HttpCookie("g")
guestCookie.Value = value
Response.Cookies.Add(guestCookie)
End Set
End Property
There are a few issues in your code, but I think the primary problem is that you are setting / creating a cookie called "g", but you are then attempting to retrieve a cookie called MYACCOUNT_SESSION_COOKIE_NAME.
You can also simplify your code by replacing your loop through the keys with a call to the property on the cookie collection that does the same thing.
Public Property IsGuest(ByVal guestStatus As String) As String
Get
Return Context.Response.Cookies(MYACCOUNT_SESSION_COOKIE_NAME).Value
End Get
Set(ByVal value As String)
Response.Cookies.Add(New HttpCookie(MYACCOUNT_SESSION_COOKIE_NAME, value)
End Set
End Property

How to get the value of an XML element using Linq even when empty

Please excuse my stupidity, I tend to find the traversing XML overly complicated.
I am using ASP.NET in VB.
I have an XML document which contains all the details of staff in my company...
<staff>
<staffName>Test Staff</staffName>
<staffTitle>Slave</staffTitle>
<staffDepartmentName>Finance</staffDepartmentName>
<staffOffice>London</staffOffice>
<staffEmail>t.staff#company.co.uk</staffEmail>
<staffPhone>0207 123 456</staffPhone>
<staffNotes>Working hours Mon to Thurs 9.15 - 5.15</staffNotes>
<staffBio></staffBio>
</staff>
As you can see, some nodes do not always contain data for ever member of staff; only Directors have biographies.
I access the values like this...
For Each staff In ( _
From matches In myXMLFile.Descendants("staff").Descendants("staffName") _
Where matches.Nodes(0).ToString.ToLower.Contains(LCase(search)) _
Order By matches.Value _
Select matches)
staffName = staff.Descendants("staffName").Nodes(0).ToString)
staffTitle = staff.Descendants("staffTitle").Nodes(0).ToString)
staffOffice = staff.Descendants("staffOffice").Nodes(0).ToString)
staffEmail = staff.Descendants("staffEmail").Nodes(0).ToString)
staffPhone = staff.Descendants("staffPhone").Nodes(0).ToString)
staffNotes = staff.Descendants("staffNotes").Nodes(0).ToString)
staffBio = staff.Descendants("staffBio").Nodes(0).ToString)
' Do something with that data...
Next
Once it gets to staffBio I get an error saying "Object reference not set to an instance of an object." obviously because that node does not exist.
My question is how can I assign the value to a variable even when it is empty without having to do a conditional check before each assignment?
First, myXMLFile.Descendants("staff").Descendants("staffName") is redundant. Descendants returns all the elements at any level within an XDocument or XElement. So, myXMLFile.Descendants("staffName") would give the same result.
Second, you can just use the Element property and the Value property like this:
staffBio = staff.Element("staffBio").Value
staff will only have one staffBio element, so there's no need to use the Descendants property. Value is a string, so you don't need to call Value.ToString. If the element is empty, then Value will return an empty string, which is what you're looking for!
Third, there is a much better (and I believe more straight forward) way of doing this in VB.NET. Here's a console app that demonstrates how I would do this:
Module Module1
Sub Main()
Dim myXMLFile = <allStaff>
<staff>
<staffName>Test Staff</staffName>
<staffTitle>Slave</staffTitle>
<staffDepartmentName>Finance</staffDepartmentName>
<staffOffice>London</staffOffice>
<staffEmail>t.staff#battens.co.uk</staffEmail>
<staffPhone>0207 123 456</staffPhone>
<staffNotes>Working hours Mon to Thurs 9.15 - 5.15</staffNotes>
<staffBio></staffBio>
</staff>
<staff>
<staffName>Other Staff</staffName>
<staffTitle>Master</staffTitle>
<staffDepartmentName>IT</staffDepartmentName>
<staffOffice>Oxford</staffOffice>
<staffEmail>o.staff#battens.co.uk</staffEmail>
<staffPhone>0207 123 789</staffPhone>
<staffNotes></staffNotes>
<staffBio>Some guy.</staffBio>
</staff>
</allStaff>
Dim search = "Test"
Dim searchQuery = From staff In myXMLFile...<staff> _
Where staff.<staffName>.Value.Contains(search) _
Select si = New StaffInfo With {.Name = staff.<staffName>.Value, _
.Title = staff.<staffTitle>.Value, _
.Department = staff.<staffDepartmentName>.Value, _
.Office = staff.<staffOffice>.Value, _
.Email = staff.<staffEmail>.Value, _
.Phone = staff.<staffPhone>.Value, _
.Notes = staff.<staffNotes>.Value, _
.Bio = staff.<staffBio>.Value}
For Each staff In searchQuery
Console.WriteLine("Name: {0}", staff.Name)
Console.WriteLine("Title: {0}", staff.Title)
Console.WriteLine("Department: {0}", staff.Department)
Console.WriteLine("Office: {0}", staff.Office)
Console.WriteLine("Email: {0}", staff.Email)
Console.WriteLine("Phone: {0}", staff.Phone)
Console.WriteLine("Notes: {0}", staff.Notes)
Console.WriteLine("Bio: {0}", staff.Bio)
Console.WriteLine()
Next
Console.ReadLine()
End Sub
Private Class StaffInfo
Private _name As String
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal value As String)
_name = value
End Set
End Property
Private _title As String
Public Property Title() As String
Get
Return _title
End Get
Set(ByVal value As String)
_title = value
End Set
End Property
Private _department As String
Public Property Department() As String
Get
Return _department
End Get
Set(ByVal value As String)
_department = value
End Set
End Property
Private _office As String
Public Property Office() As String
Get
Return _office
End Get
Set(ByVal value As String)
_office = value
End Set
End Property
Private _email As String
Public Property Email() As String
Get
Return _email
End Get
Set(ByVal value As String)
_email = value
End Set
End Property
Private _phone As String
Public Property Phone() As String
Get
Return _phone
End Get
Set(ByVal value As String)
_phone = value
End Set
End Property
Private _notes As String
Public Property Notes() As String
Get
Return _notes
End Get
Set(ByVal value As String)
_notes = value
End Set
End Property
Private _bio As String
Public Property Bio() As String
Get
Return _bio
End Get
Set(ByVal value As String)
_bio = value
End Set
End Property
End Class
End Module
If you have a schema (.xsd file) for your XML, then you can import a reference to that xmlns to your VB source file, which will give you intellisense for writing your LINQ to XML queries.
(Edit: A quick way to create a schema is to open up an XML file in Visual Studio and choose Create Schema from the XML menu.)
For more information and help, please check out the "How Do I" video series on LINQ by Beth Massi.
OK think this is how to do it.
...
staffBio = staff.Descendants("staffBio").ElementAtOrDefault(0).Value.ToString)
...
Using .ElementAtOrDefault(0) instead of .Nodes(0) just returns "" if it's empty or <staffBio>whatever</staffBio> if it is not.
.Value just returns the content of the tags like "whatever" in the example above.
Is this right? Can anyone see any problems with this?

Resources