Search code examples
c#serializationforeachbinaryformatterbinary-serialization

How to loop through a file to get data?


I am trying to make a basic login and sign up c# console application, however, I need to loop through my file to see if the username and password the user inputted has a match when logging in. If the user types in a username and password, I want my code to go through my file to check if it is an existing username and password

Here is my code:

[Serializable]
public class Users
{
    public string UserName;
    public string Password;

    public Users(string userName, string password)
    {
        UserName = userName;
        Password = password;
    }
}

public class SaveToFile
{
    public static void SerializeSignUpDetails(string userName, string password)
    {
        Users obj = new Users(userName, password);
        IFormatter formatter = new BinaryFormatter();
        Stream stream = new FileStream("SignUp.txt", FileMode.Append, FileAccess.Write);
        formatter.Serialize(stream, obj);
        stream.Close();
    }
    public static Users DeserializeSignUpDetails()
    {
        Stream stream = new FileStream("SignUp.txt", FileMode.Open, FileAccess.Read);
        IFormatter formatter = new BinaryFormatter();
        Users objnew = (Users)formatter.Deserialize(stream);
        stream.Close();
        return objnew;
    }
}

public static void Main(string[] args)
{
    Console.WriteLine("To Login Type 1, To Create a new account Type 2");
    int LogInOrSignUp;
    do
    {
        int.TryParse(Console.ReadLine(), out LogInOrSignUp);
    } while (LogInOrSignUp != 1 && LogInOrSignUp != 2);

    string userName = "";
    string password = "";
    bool successfull = false;
    Users userDetails = SaveToFile.DeserializeSignUpDetails();
    while (!successfull)
    {
        if (LogInOrSignUp == 1)
        {
            Console.WriteLine("Write your username:");
            userName = Console.ReadLine();
            Console.WriteLine("Enter your password:");
            password = Console.ReadLine();
            if (userName == userDetails.UserName && password == userDetails.Password)
            {
                Console.WriteLine("You have logged in successfully!");
                successfull = true;
                break;
            }
            if (!successfull)
            {
                Console.WriteLine("Your username or password is incorect, try again!");
            }
        }

        else if (LogInOrSignUp == 2)
        {
            Console.WriteLine("Enter a username:");
            userName = Console.ReadLine();

            Console.WriteLine("Enter a password:");
            password = Console.ReadLine();

            successfull = true;
            SaveToFile.SerializeSignUpDetails(userName, password);
        }
    }
}

I want to use foreach to loop through my file, but I am not sure how.

Any help appreciated!


Solution

  • To keep a login record for multiple entries using serialization, you need to serialize a list of objects. In your case, you could create a couple of serializable classes, User class that encapsulates the data of a single entry, and Users class that contains a List<User> objects plus the data manipulation methods.

    ✔ Note: Name as you prefer.

    Namespaces to import

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.IO;
    using System.Runtime.Serialization.Formatters.Binary;
    

    The User class

    [Serializable]
    public class User
    {
        public string UserName { get; set; }
        public string Password { get; set; }
        //More details...
    
        public User(string userName, string password)
        {
            UserName = userName;
            Password = password;
        }
    
        public override string ToString() => $"{UserName}, {Password}";
    }
    

    The Users class

    [Serializable]
    public class Users
    {
        public readonly List<User> Accounts;
    
        public Users() => Accounts = new List<User>();
    
        public void Save(string filePath)
        {
            if (string.IsNullOrEmpty(filePath)) return;
    
            var bf = new BinaryFormatter();
            using (var fs = new FileStream(filePath, FileMode.Create))
                bf.Serialize(fs, this);
        }
    
        public static Users Load(string filePath)
        {
            if (!File.Exists(filePath)) return null;
    
            var bf = new BinaryFormatter();
            using (var sr = new FileStream(filePath, FileMode.Open))
                return bf.Deserialize(sr) as Users;
        }
    
        public bool ContainsUserName(string userName) => 
            Accounts.Any(x => x.UserName == userName);
    
        public bool ContainsAccount(string userName, string pass) =>
            Accounts.Any(x => x.UserName == userName && x.Password == pass);
    
        public User Get(string userName, string pass) =>
            Accounts.FirstOrDefault(x => x.UserName == userName && x.Password == pass);
    
        public bool Add(string userName, string pass)
        {
            if (ContainsUserName(userName)) return false;
    
            Accounts.Add(new User(userName, pass));
            return true;
        }
    }
    

    In your implementation, to create, load, and save your data:

    //Load...
    users = Users.Load(dataFilePath);
    
    //Or create new object...
    if (users is null)
        users = new Users();
    
    //and when it comes to save...
    users.Save(dataFilePath);
    

    Use the ContainsUserName method to find out whether a given username is already exist so you can avoid the duplicates. The Add method will do the same plus it will add the valid new entries into the list. The Get method searches the list for the given username and password and returns a User object if any otherwise null, and the ContainsAccount method will do the same if you don't need to return a User object.

    var user = users.Get("user", "pass");
    if (user is null)
        Console.WriteLine("Incorrect username and/or password...");
    
    //or
    if (!users.ContainsAccount("user", "pass"))
        Console.WriteLine("Incorrect username and/or password...");
    

    Applying that in your main:

    public static void Main(string[] args)
    {
        Console.WriteLine("To Login Type 1, To Create a new account Type 2");
        int LogInOrSignUp;
        do
        {
            int.TryParse(Console.ReadLine(), out LogInOrSignUp);
        } while (LogInOrSignUp != 1 && LogInOrSignUp != 2);
    
        var filePath = Path.Combine(AppContext.BaseDirectory, "SignUp.dat");
        var userName = "";
        var password = "";
        var successfull = false;
        var userDetails = Users.Load(filePath);
    
        if (userDetails is null)
            userDetails = new Users();
    
        while (!successfull)
        {
            if (LogInOrSignUp == 1)
            {
                Console.WriteLine("Write your username:");
                userName = Console.ReadLine();
                Console.WriteLine("Enter your password:");
                password = Console.ReadLine();
                if (userDetails.ContainsAccount(userName, password))
                {
                    Console.WriteLine("You have logged in successfully!");
                    successfull = true;
                    break;
                }
                else
                    Console.WriteLine("Your username or password is incorect, try again!");
            }
    
            else //if (LogInOrSignUp == 2)
            {
                Console.WriteLine("Enter a username:");
                userName = Console.ReadLine();
    
                if (userDetails.ContainsUserName(userName))
                    Console.WriteLine("The username is taken. Try another one.");
                else
                {
                    Console.WriteLine("Enter a password:");
                    password = Console.ReadLine();
    
                    successfull = true;
                    userDetails.Add(userName, password);
                    userDetails.Save(filePath);
                    Console.WriteLine($"A new account for {userName} has been created.");
                }
            }
        }
        Console.ReadLine();
    }
    

    ✔ Note: Better to use the switch statement to select LogInOrSignUp instead of the if statements

    SOQ62185878