2
\$\begingroup\$

Currently on my ASP.NET website when I define a new user I write their data to a .txt file like this:

public class User
{
public string UserName;
public string PassWord;
public string Email;
public string FirstName;
public string LastName;
public string Twitter;
public string FaceBook;
public int Age;
public DateTime DateCreated;

public User(string username, string password, string email, string facebook, string twitter, string firstname, string lastname, int age, DateTime datecreated)
{
    UserName = username;
    PassWord = password;
    Email = email;
    FirstName = firstname;
    LastName = lastname;
    Age = age;
    DateCreated = datecreated;
    Twitter = twitter;
    FaceBook = facebook;

    AddToTextFile();
}

public bool CheckUsername(string username, List<User> users)
{
    for (int i = 0; i < users.Capacity; i++)
    {
        if (users[i].UserName == username) return true;

        else return false;
    }

    return false;
}

public bool CheckPassword(string username, string password, List<User> users)
{
    for (int i = 0; i < users.Capacity; i++)
    {
        if (users[i].UserName == username)
        {
            if (users[i].PassWord == password) return true;

            else return false;
        }

        else return false;
    }

    return false;
}

private void AddToTextFile()
{
    string file = "../users-information.txt";
    StreamWriter sw = new StreamWriter(@file);
    sw.WriteLine("{0} {1} {2} {3} {4} {5} {6} {7} {8}", UserName, PassWord, FirstName, LastName, Email, FaceBook, Twitter, Age, DateCreated); 
}

Then on my C# app I use WebClient.DownloadData to get the data and write it to a file.

    private void GetUsers()
    {
        //JavaScriptSerializer serializer = new JavaScriptSerializer();
        //users = serializer.Deserialize<User[]>(Request.Form["users"]);

        WebClient client = new WebClient();
        byte[] file = client.DownloadData("http://kinected-security.com/users-information.txt");

        File.WriteAllBytes(@"../user-information/user-information.txt", file);

        string[] lines = File.ReadAllLines("../user-information/user-information.txt");

        if (lines.Length != 0)
        {
            foreach (string line in lines)
            {
                string[] splited = new string[]{ };
                splited = line.Split(new Char[] {' ' });

                users.Add(new User(splited[0], splited[1], splited[2], splited[3], splited[4], splited[5], splited[6], int.Parse(splited[7]), DateTime.Parse(splited[8])));
            }
        }
    }

Should I be using WebClient.DownloadString? Is there a more efficient way to do this?

\$\endgroup\$
2
\$\begingroup\$

You don't have to write the file and read it again. You can change the byte array to a string internally using an Encoding and GetString() and split it by new line. Or you can do DownloadString directly and split by line. Reading/writing seems wasteful. Note that you might want to have some security around downloading user information from your server.

\$\endgroup\$
  • \$\begingroup\$ I do have security I just didn't post it, and can you show an example of the encoding? Thanks \$\endgroup\$ – Liam McInroy Aug 8 '12 at 17:28
  • \$\begingroup\$ Sure, you can do something like: string Contents = Encoding.UTF8.GetString(byte_array_here). Then, you can split it, like so: string[] lines = Contents.split("\r\n"). \$\endgroup\$ – Roel van Uden Aug 8 '12 at 17:28
  • \$\begingroup\$ I will try it and accept if it works \$\endgroup\$ – Liam McInroy Aug 8 '12 at 17:29
  • \$\begingroup\$ I'm sorry, it should be Regex.Split(Contents, "\r\n"). \$\endgroup\$ – Roel van Uden Aug 8 '12 at 17:33
  • \$\begingroup\$ Oh also I understand the "\n" but why "\r" \$\endgroup\$ – Liam McInroy Aug 8 '12 at 17:34
3
\$\begingroup\$

Here is my cleanup of the User class. Note that there is a world of a difference between the .Count and the .Capacity properties of a list. Look them up! Your CheckUsername and CheckPassword methods were broken in more than one way.

namespace Foo
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;
    using System.IO;
    using System.Linq;

    public class User
    {
        private static readonly string filePath = "../users-information.txt"; // Or not readonly if you wish to set it at run time.

        public User(IList<string> tokens)
        {
            Contract.Requires(tokens.Count == 9, "Expected exactly 8 tokens but got " + tokens.Count + " of them.");
            int age = Convert.ToInt32(tokens[7]);
            DateTime dateCreated = Convert.ToDateTime(tokens[8]);

            this.Init(
                userName : tokens[0],
                password: tokens[1],
                email: tokens[2],
                facebook: tokens[3],
                twitter: tokens[4],
                firstName: tokens[5],
                lastName: tokens[6],
                age: age,
                dateCreated: dateCreated);
        }

        public User(
            string username,
            string password,
            string email,
            string facebook,
            string twitter,
            string firstname,
            string lastname,
            int age,
            DateTime dateCreated)
        {
            this.Init(username, password, email, facebook, twitter, firstname, lastname, age, dateCreated);
        }

        public string UserName
        {
            get;
            private set;
        }

        public string PassWord
        {
            get;
            private set;
        }

        public string Email
        {
            get;
            private set;
        }

        public string FirstName
        {
            get;
            private set;
        }

        public string LastName
        {
            get;
            private set;
        }

        public string Twitter
        {
            get;
            private set;
        }

        public string FaceBook
        {
            get;
            private set;
        }

        public int Age
        {
            get;
            private set;
        }

        public DateTime DateCreated
        {
            get;
            private set;
        }

        private void Init(
            string userName,
            string password,
            string email,
            string facebook,
            string twitter,
            string firstName,
            string lastName,
            int age,
            DateTime dateCreated)
        {
            this.UserName = userName;
            this.PassWord = password;
            this.Email = email;
            this.FirstName = firstName;
            this.LastName = lastName;
            this.Age = age;
            this.DateCreated = dateCreated;
            this.Twitter = twitter;
            this.FaceBook = facebook;

            this.AddToTextFile();
        }

        /***** These methods are not great:
        A) It is not safe to send plain-text passwords over the wire as well as well as store them as such. You would want to compare a very well crafted and tested "hash code"/checksum.
        B) This has O(n) run time. Dictionary or a set would be a better data structure. You probably want a dictionary that maps a user name to a pair `[userName, hash]` and a dictionary that maps `hash` to the same pair. Maybe you will need a database, but a linear list is not as great.

        // Unused?
        public static bool CheckUsername(string username, IList<User> users)
        {
            return users.Any(user => user.UserName.Equals(username, StringComparison.Ordinal)); // Case-sensitive?
        }

        // Unused? Not the best method name - CheckCredentials perhaps?
        public static bool CheckPassword(string username, string password, List<User> users)
        {
            return users.Any(user => user.UserName.Equals(username, StringComparison.Ordinal)  // Case-sensitive?
                && user.PassWord.Equals(password, StringComparison.Ordinal));
        }
        */

        private void AddToTextFile()
        {
            using (var sw = new StreamWriter(filePath))
            {
                sw.WriteLine(
                    "{0} {1} {2} {3} {4} {5} {6} {7} {8}",
                    this.UserName,
                    this.PassWord,
                    this.FirstName,
                    this.LastName,
                    this.Email,
                    this.FaceBook,
                    this.Twitter,
                    this.Age,
                    this.DateCreated);
            }
        }
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.