Simplify ASP.Net StreamWriter for appendtext to file
Careful with naming.

UserName is an identifier for a TextBox, but it's named like a String (which contains a user's name).

I'd declare and assign UserName like this:

Dim UserName As String = DirectCast(LoginUser.FindControl("UserName"), TextBox).Text


And now the rest of the code can refer to a string that represents a user's name without any further conversions.



logLoginError is an identifier for a Thread, but it's named like a Task (which runs on a thread).

loggerThread would be a more accurate name for it.



This code:

w.WriteLine(CurrentUser.ToString &amp; "'s (" &amp; IPAddress &amp; ") account is locked out - " &amp; DateAndTime.Now)


Is using way more String instances than you'd think:


CurrentUser.ToString()
"'s ("
IPAddress
") account is locked out - "
DateAndTime.Now[.ToString]


And also:


The string resulting from CurrentUser.ToString() &amp; "'s ("
The string resulting from CurrentUser.ToString() &amp; "'s (" &amp; IPAdress
The string resulting from CurrentUser.ToString() &amp; "'s (" &amp; IPAdress &amp; ") account is locked out - "
The string resulting from CurrentUser.ToString() &amp; "'s (" &amp; IPAdress &amp; ") account is locked out - " &amp; DateAndTime.Now


Are you sure DateAndTime isn't supposed to be DateTime? Also there's a typo in IPAdress, should be IPAddress.

To fix the number of String objects being created, you can use String.Format instead of inline concatenations - remember that String is an immutable class, "appending to it" doesn't really append anything, it just creates a new instance.

This would be cleaner and more efficient (multiline to avoid horizontal scrolling):

w.WriteLine(String.Format("{0}'s ({1}) account is locked out - {2}", 
                          CurrentUser.ToString, IPAddress, DateAndTime.Now))