I created a class User, which contain simple variables as shown below:
public class User
{
public string username; //Unique usernames
public string password;
}
I then instantiate a list of an object in another class:
List<User> user = new List<User>();
user.Add(new User {username = "admin", password = "123"});
How is it possible for me to retrieve the password's value by searching for the username using a foreach loop? I am probably just confused but this is what I came up with:
foreach(var item in user)
{
if(item.Equals(username_input))
{
//I try to store the password into a string pass_check
pass_check = item.password;
}
}
if (user_input.Equals(pass_check))
{
Console.WriteLine("Login successful");
}
Sorry if this seems like a dense question to anyone out there, still a beginner trying to learn!
You're pretty close..
if(item.username.Equals(username_input))
You need to check the property of the item in this case which is username.
You could even shorten it to:
foreach(var item in user)
{
if(item.username.Equals(username_input)
&& user_input.Equals(item.password))
{
Console.WriteLine("Login successful");
break; // no need to check more.. or is there?
}
}
You can get really fancy using Linq:
if (user.Any(i => i.username.Equals(username_input)
&& user_input.Equals(i.password))
{
Console.WriteLine("Login successful");
}
As juharr noted in the commend, best practices for exposing values from class/objects is to use Properties not Fields..
public class User
{
// not best practices
public string username;
// best practices
public string password { get; set; }
}
Even fancier:
using System.Linq;
public static class Extensions
{
// Extension method that works on List<User> to validate user && PW
// - returns true if user exists and pw is ok, else false
public static bool CheckUserPassword(this List<User> users, string user_name, string pw)
{
// add null checks for users, user_name and pw if you are paranoid of know your customers ;o)
return users.Any(u => u.username == user_name && u.password == pw);
}
}
public class User
{
public string password;
public string username; //Unique usernames
}
internal class Program
{
private static List<User> users = new List<User> { new User { username = "admin", password = "123" } };
static void Main(string[] args)
{
// use extension method like this:
var isValid = users.CheckUserPassword("Hello","Jeha");
Console.WriteLine($"user 'admin' with pw '8888' => {users.CheckUserPassword("admin", "8888")}");
Console.WriteLine($"user 'admin' with pw '123' => {users.CheckUserPassword("admin", "123")}");
Console.ReadLine();
}
}
Extension Methods can be executed on the this-part - in this case only on List<User>s. The Extensionmethod uses Linq to find if Any (at least 1) user of this name and pw exists.
Related
I'm trying to create a class called User that can register new Users and store them in a list. Currently, I just want to be able to use the RegisterUser object. I have a C# book and have tried understanding it, but it's not clicking. Any help or hints in the right direction are very much appreciated.
namespace UserClass {
/// <summary>
/// The user class
/// <summary>
public class User {
public string userName;
public string password;
public string address;
public int contactNumber;
public static RegisterUser(string username, string pass, string add, int contact) {
User newUser = new User();
newUser.userName = username;
newUser.password = pass;
newUser.address = add;
newUser.contactNumber = contact;
WriteLine(newUser);
};
}
}
A few issues with your code:
WriteLine is incorrect unless you've created that method
I think you're looking for Console.WriteLine(...) which you can
use after adding using System; however even that would be
incorrect.
I assume you are looking to print the values of fields in
the User class which in that case, either override .ToString
(bad idea) or access and print them separately.
RegisterUser has no return type
It could be void -> public static void RegisterUser(string username, string pass, string add, int contact) indicating that nothing is returned.
However, common convention and expectation would be that the new User object is returned so that the caller can know what the final state of the operation was ->
You have a rogue ; at the end of the implementation of RegisterUser(...)
You need to remove it to make your code compile.
You actually have no variables anywhere, which would allow you to create a collection
You need to add your users to something like a List<User>, which would be encapsulated internally in another class perhaps called UserManager. This allows you to expose behaviour but hide the implementation, as well as adhering to SRP.
You could then expose the collection of users if you needed to, in a clear way, using a ReadOnlyCollection<User>.
This would show consumers that they would probably have to call a method (RegisterUser) to be able to add to the collection of users as ReadOnlyCollection<User> prevents modification, and not just do users.Add(...) & bypass your registration logic.
In this case, RegisterUser would also not have the static keyword, as it would need access to the instance field - your collection of users - and it won't be able to do that as a static method.
Your namespace is extremely specific to your User class
It's technically okay but namespaces are used to organise classes & control scope. I would rename it to something more related to your domain, as opposed to something bound to your class name (UserClass).
Arguments for RegisterUser
I would also cut down on the number of arguments to RegisterUser, take in a User object and then enforce all fields being set using the constructor for User.
This would turn it into a monadic method, making the code more readable, easier to test later on and makes you keep a conscious tab on how many "things" the method is responsible for.
Something like the below should work:
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace MyApplication
{
public class User
{
public string UserName;
public string Password;
public string Address;
public int ContactNumber;
public User(string username, string pass, string add, int contact)
{
UserName = username;
Password = pass;
Address = add;
ContactNumber = contact;
}
}
public class UserManager
{
private readonly List<User> _users = new List<User>();
public ReadOnlyCollection<User> GetUsers()
{
return _users.AsReadOnly();
}
public User RegisterUser(User newUser)
{
// process user, modify fields, add etc.
_users.Add(newUser);
return newUser;
}
}
public static class UserOutput
{
public static void WriteUserToConsole(User user)
{
Console.WriteLine($"{user.UserName}, {user.Password}, {user.Address}, {user.ContactNumber}");
}
}
}
var userManager = new UserManager();
var userToBeRegistered = new User("A", "B", "C", 0);
var createdUser = userManager.RegisterUser(userToBeRegistered);
UserOutput.WriteUserToConsole(createdUser);
var allUsers = userManager.GetUsers();
foreach (var user in allUsers)
UserOutput.WriteUserToConsole(user);
you are nearly there
public class User
{
public string userName;
public string password;
public string address;
public int contactNumber;
}
// Separate Class to create and store the users
public class UserController
{
// List to store your Users
public List<User> UserList;
// Constuctor instatiates UserList
public UserController()
{
UserList = new List<User>();
}
public void RegisterUser(string username, string pass, string add, int contact) {
User newUser = new User();
newUser.userName = username;
newUser.password = pass;
newUser.address = add;
newUser.contactNumber = contact;
// Adding the user to the UserList
UserList.Add(newUser);
// Show the userName of the new User in Console
Console.WriteLine(newUser.userName);
}
}
you can now Register users with your method in the new separate class. They will be stored in the UserList that you can access freely from outside of the class.
usage:
//get a UserController to start working
UserController controller = new UserController();
// call to RegisterUser
controller.RegisterUser("bob", "1234", "mystreet 1", 42);
I feel like you are close. See if the following points will help.
RegisterUser is a function/method with no purpose as it is missing a return type specification. Here you have two design options:
Create a new user and return a variable referencing this user.
static User RegisterUser( ... )
{
newUser = new User();
...
return newUser;
}
Create a new user and store the user internally to a list. This means the function specification must have void in its return type.
static List<User> userList = new List<User>();
static void RegisterUser( ... )
{
newUser = new User();
...
userList.Add(newUser);
}
You can specify the required information to define a user by declaring a constructor which assigns this information when a new User object is created. For example, if the username and password are the only required field then
Create a constructor accepting these two values
public class User
{
...
public User(string userName, string password)
{
this.userName = userName;
this.password = password;
}
}
Change the fields on readonly such that they cannot be modified at a later time.
public class User
{
public readonly string userName;
public readonly string password;
public string address;
public int contactNumber;
...
}
There is no defined way to display the information for each user on the console and so a call to Console.WriteLine(user) will only display the user type (default behavior of C#). To add this functionality to a class, override the ToString() method.
public class User
{
...
public override string ToString()
{
return $"User = {userName}, Address = {address}, Contact = {contactNumber}";
}
}
Now in the main program when you loop through the registered users, you can simply invoke Console.WriteLine() on each one to show on the screen the information.
static void Main(string[] args)
{
User.RegisterUser("aaa", "abc1", "100 east", 55500);
User.RegisterUser("xyz", "uvw5", "120 north", 55501);
foreach (var user in User.registededUsers)
{
Console.WriteLine(user);
}
}
it is common practice to hide fields behind properties. In this case it would be useful not to expose the list of registered users outside of the class as List<User> because it will allow the addition of new items in the list without requiring to call the RegisterUser() function. To disallow this behavior remove the public from the registededUsers field and add a property called RegisteredUsers expose this field as a IReadOnlyList<User>
public class User
{
...
static List<User> registededUsers = new List<User>();
public static IReadOnlyList<User> RegisteredUsers { get => registededUsers.AsReadOnly(); }
}
public async Task<IActionResult> Register(RegisterUserVM userVM)
{
if(!ModelState.IsValid) return View();
AppUser user = new AppUser
{
Name = userVM.Name,
Email = userVM.Email,
Surname = userVM.Surname,
UserName = userVM.Username
};
var result = await _userManager.CreateAsync(user,userVM.Password);
if (!result.Succeeded)
{
foreach (var item in result.Errors)
{
ModelState.AddModelError("", "ur username or password invalid");
return View();
}
}
return RedirectToAction("Index", "Home");
}
enter code here
public async Task<IActionResult> Login(LoginUserVM userVM)
{
if(!ModelState.IsValid) return View();
var user = await _userManager.FindByNameAsync(userVM.UsernameorEmail);
if(user == null)
{
user = await _userManager.FindByEmailAsync(userVM.UsernameorEmail);
if (user == null)
{
ModelState.AddModelError("", "ur username or password invalid");
return View();
}
}
var result = await _signInManager.PasswordSignInAsync(user, userVM.Password, userVM.IsPersistance, true);
if (!result.Succeeded)
{
ModelState.AddModelError("", "ur username or password invalid");
return View();
}
return RedirectToAction("Index","Home");
}
I am creating a static sign in page using List to save the data. I am using a ForEach to loop through the list but the issue I am facing is I want my for loop to stop immediately the condition is true.
NB: I have tried using a break and a return but they are not working as expected.
The code is here:
List<User> users = new List<User>(3);
public MainWindow()
{
InitializeComponent();
User superAdmin = new User()
{
userType = "Super Admin",
uniqueCode = "123456",
password = "password1"
};
User admin = new User()
{
userType = "Admin",
uniqueCode = "654321",
password = "password16"
};
User userOperator = new User()
{
userType = "Operator",
uniqueCode = "109105",
password = "specialpassword"
};
users.Add(superAdmin);
users.Add(admin);
users.Add(userOperator);
}
private void login_OnClick(object sender, RoutedEventArgs e)
{
string userType = cmbAdminType.Text;
string uniqueCode = txtUniqueCode.Text;
string password = txtPassword.Text;
foreach (User userPick in users)
{
if (userPick.userType == userType && userPick.uniqueCode == uniqueCode)
{
MessageBox.Show("Cool you are in!");
break;
}
else
{
MessageBox.Show("Err, not found!");
break;
}
}
}
}
public class User
{
public string userType { get; set; }
public string uniqueCode { get; set; }
public string password { get; set; }
}
Please, what else can I do?
Others have pointed out the flaw in your current code, but I'd suggest using a LINQ approach here. It's much shorter and easier to read - at least when you're used to LINQ:
bool validUser = users.Any(user => user.userType == userType && user.uniqueCode == uniqueCode);
MessageBox.Show(validUser ? "Cool you are in!" : "Err, not found!");
Any is short-circuiting: it stops as soon as it finds a match.
As a side-note, I'd strongly encourage you to start following .NET naming conventions for your properties.
I believe that this could be because you have a logical error in the way that your code is working.
Currently, you break from your foreach loop on the first successful match, or the first unsucessful match. So basically, your enumeration will break after 1 iteration whether successful or not.
You could introduce a flag that you use to record success, or not, and then test this after the enumeration, as so:
private void login_OnClick(object sender, RoutedEventArgs e)
{
string userType = cmbAdminType.Text;
string uniqueCode = txtUniqueCode.Text;
string password = txtPassword.Text;
bool isMatched = false;
foreach (User userPick in users)
{
if (userPick.userType == userType && userPick.uniqueCode == uniqueCode)
{
isMatched = true;
break;
}
}
if (isMatched)
{
MessageBox.Show("Cool you are in!");
}
else
{
MessageBox.Show("Err, not found!");
}
}
Your loop stops after the first object found in the list. I think what you want to accomplish is that it breaks either when the object you looked for is found either at the end of the loop, if the object you were looking for had not been found. The code:
bool userInside = false;
foreach (User userPick in users)
{
if (userPick.userType == userType && userPick.uniqueCode == uniqueCode)
{
MessageBox.Show("Cool you are in!");
userInside=true;
break;
}
}
if (userInside==false)
{
MessageBox.Show("Err, not found!");
}
I hope this helps. ^^
string currentUser;
string currentPassword;
string getUserName;
string getPassword;
getUserName = Convert.ToString(Session["UserName"]);
getPassword = Convert.ToString(Session["Password"]);
currentUser = Convert.ToString(txtUserNameLogIn.Text);
currentPassword = Convert.ToString(txtPasswordLogin.Text);
if ((currentUser == getUserName ) && (currentPassword == getPassword)) {
currentUser = Convert.ToString(Session["CurrentUser"]);
currentPassword = Convert.ToString(Session["CurrentPassword"]);
Response.Redirect("Home.aspx");
} else {
lblResult.Text = "Invalid Password";
}
I have 3 pages. First one for registration, that saves UserName and Password so a Session and then I have login page that should take the UserName and Password sessions and compare them to the current user input on this page. So far I'm not getting any responses.
Edit: The username and password that I put in on previous page gets stored in a Session Variable called "UserName", the person gets re-directed to login page and I simply want to compare what user types in with the Session Variable from previous page and if it's correct, store that information in new Session Variable and re-direct user to home page.
You can do several things here working under the assumption this is a test project and you know Session is not the correct place to store plaintext credentials. Take a look at SimpleMembership for a cleaner approach.
That out of the way I created two extension classes. The first takes care of string security, and the second takes care of Session. You can take this a step further and create constants for the keys or even a SessionUser object. In terms of comparison I just combined both username+password so the logic is short.
public static class StringExtensions
{
public static string Encrypt(this string plainText)
{
// Replace with your encryption impl
return plainText;
}
public static string Decrypt(this string hiddenText)
{
// Replace with your decryption impl
return hiddenText;
}
}
public static class SessionExtensions
{
public static void Set<T>(this HttpSessionState sessionState, string key, T value)
{
sessionState[key] = value;
}
public static T Get<T>(this HttpSessionState sessionState, string key) where T : class
{
return (T)sessionState[key];
}
}
public partial class _Default : Page
{
protected void Page_Load(object sender, EventArgs e)
{
Session.Set("UserName", "something");
Session.Set("Password", "something".Encrypt());
var username = Session.Get<string>("UserName");
var password = Session.Get<string>("Password").Decrypt();
var savedUser = $"{username}{password}";
var currentUser = $"somethingsomething";
if (currentUser.Equals(savedUser, StringComparison.InvariantCultureIgnoreCase))
{
}
else
{
}
}
}
I'm using the code below to get various information about the logged in user and it works, but I want to turn it into a method where I can pass the attribute I want (DisplayName, EmailAddress, etc) and it returns that value for whoever is logged in. I couldn't figure out how to get this to work though.
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(context, User.Identity.Name))
{
if (user != null)
{
loggedInUserfullName = user.DisplayName;
loggedInUserEmail = user.EmailAddress;
}
}
}
While the above works, I can't use any of those variables outside of the scope of the method, which isn't helpful.
I tried the method below to just get the DisplayName but got errors due to FindByIdentity expecting a string (I don't have a string with the user's name - that's what I'm trying to find out!)
public string getUserFullName(object user)
{
user = UserPrincipal.FindByIdentity(ContextType.Domain, user);
string loggedInUserDisplayName = user.DisplayName;
return loggedInUserDisplayName ;
}
UserPrincipal loggedInUser = new UserPrincipal(ContextType.Domain);
// line above throws cannot convert from 'System.DirectoryServices.AccountManagement.ContextType' to 'System.DirectoryServices.AccountManagement.PrincipalContext'
getUserDetails(loggedInUser);
Is there a way to do this? Am I using the wrong library to achieve what I want?
This is a web application using windows authentication, if that makes any difference.
Thanks
I haven't used the DirectoryServices.AccountManagement stuff in a long time, but I'll give this a shot.
This line in your code is throwing an exception:
UserPrincipal loggedInUser = new UserPrincipal(ContextType.Domain);
The exception is telling you that the constructor for UserPrincipal expects a System.DirectoryServices.AccountManagement.PrincipalContext, but you're giving it a System.DirectoryServices.AccountManagement.ContextType. These lines in your working code are correct:
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(context, User.Identity.Name))
{
I'm not sure I fully understand what your intention is, but if you are looking for a reusable way to get info about the logged in user, try something like this:
public static class UserManager
{
public static string GetDisplayName(string name)
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain), name))
{
if (user != null)
{
return user.DisplayName;
}
throw new Exception("error");
}
}
}
You can call it by doing this:
var dn = UserManager.GetDisplayName(User.Identity.Name);
Obviously, you'll want to handle the error better. If I'm missing something, let me know and I'll try to update my answer.
Hope this helps!
Edit
To return an object containing multiple fields, you could do something like:
public static UserInfo GetDisplayName(string name)
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(new PrincipalContext(ContextType.Domain), name))
{
if (user != null)
{
return new UserInfo
{
FullName = user.DisplayName,
Email = user.EmailAddress,
GivenName = user.GivenName,
SamAccountName = user.SamAccountName,
Surname = user.Surname
//any other things you may need somewhere else
};
}
throw new Exception("error");
}
}
Here is the UserInfo class:
public class UserInfo
{
public string FullName { get; set; }
public string Email { get; set; }
public string Surname { get; set; }
public string GivenName { get; set; }
public string SamAccountName { get; set; }
}
I have two classes: User and Site. User and Site have a many-to-many relationship. A Site object S has a property indicating whether or not a User U should be validated before U is added to S. To validate a User, the application retrieves validation rules from the Site and checks to see that the User's properties' values match the validation rules' values. If they all match/pass, the User is "valid" to be added to that Site.
How would you structure this relationship? My first thought is to create an intermediate class (i.e. Mediator design pattern?) that has a field of type IEnumerable<User> and Site so I can encapsulate the Site validation setting retrieval. Also, I'm thinking of adding an "IsValid" property to the User class. Is that all I need? I want to make sure things are not tightly coupled.
Thoughts?
Here's similar code I wrote up:
public class User
{
public int _userId;
public string _fname;
public string _lname;
public User(string connectionString, int id)
{
using (var dc = new DataContext(connectionString))
{
var user = dc.Users.SingleOrDefault(u => u.ID == id);
_userId = user.ID;
_fname = user.FName;
_lname = user.LName;
}
}
public bool IsValidUser(int siteId)
{
bool isValid = true;
// logic here probably won't change
var conditions = Site.GetConditions(_userId);
// e.g. checks _fname, _lname
return Site.UserMeetsConditions(_id, conditions);
}
}
public class Site
{
public int _siteId;
public List<Setting> _siteSettings;
public Site(string connectionString, int id)
{
using (var dc = new DataContext(connectionString))
{
var site = dc.Sites.SingleOrDefault(u => u.ID == id);
_siteId = site.ID;
}
}
public void SetSiteSettings(string connectionString)
{
using (var dc = new DataContext(connectionString))
{
_siteSettings = dc.SiteSettings.Select(s => s).ToList();
}
}
public bool SiteRequiresValidityCheck()
{
return _siteSettings.Any(s => s.SettingID = 100 && s.Value == true);
}
}
public Validator
{
public List<User> users;
public bool _requiresValidityCheck;
public bool UsersAreValid(int siteId)
{
bool usersAreValid = true;
if (_requiresValidityCheck)
{
foreach (var user in users)
{
if (!user.IsValid)
{
usersAreValid = false;
break;
}
}
}
return usersAreValid;
}
}
static void Main()
{
string cs = myconnectionstring;
var user1 = new User(cs, 1);
var user2 = new User(cs, 2);
List<User> users = new List<User>() { user1, user2 };
var site = new Site(cs, 10);
site.SetSiteSettings(cs);
var validator = new Validator();
validator.Users = users;
validator._requiresValidityCheck = site.SiteRequiresValidityCheck();
bool usersAreValid = validator.UsersAreValid(site._siteId);
}
If this is a POCO class or a MODEL you could use DataAnnotations on your class attributes.
Like user
[Required]
etc attributes for each attribute.
Data annotations also has support for cross attribute checking that you can implement those too.
take a look at them here:
https://msdn.microsoft.com/en-us/library/dd901590%28VS.95%29.aspx