So I have a simple User Class:
public class User
{
public string id, name, email, image;
public User (IFBGraphUser user)
{
id = user.GetId ();
name = user.GetName ();
GetEmail ();
}
private void GetEmail()
{
FBRequestConnection.StartWithGraphPath("/me", null, "GET", delegate(FBRequestConnection connection, NSObject result, NSError error) {
var me = (FBGraphObject)result;
this.email = me["email"].ToString();
});
}
}
But I need to get the users email from Facebook. My Facebook request has a delegate and when I try to assign the email field inside the delegate, the email field remains null. How can I go about getting the email into the email field from the delegate?
Its not a problem with the facebook result, ive tried this.email = "test"; and it was still null when I went to access it.
In this Code i am setting a class level field's value and accessing it outside of delegate so this might help you, see the below given code:-
public delegate void delgJournalBaseModified(string a);
public class User
{
public string id, name, email, image;
public User(string uid,string uName)
{
id = uid;
name = uName;
Console.WriteLine(this.name);
Console.WriteLine(this.email);
GetEmail();
}
private void GetEmail()
{
set(delegate(string d)
{
this.email = d;
});
}
private void set(delgJournalBaseModified delgJournalBaseModified)
{
delgJournalBaseModified.Invoke("value is set");
Console.WriteLine(this.email);
}
}
and call like this in main method or anywhere you like..
User a1 = new User("123", "dev");
Console.WriteLine(a1.email);
now if you will the console "value is set" is being print twice.
Thanks
Devendra
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 trying to create a function GetUserID() which returns the userID, which I have inserted into a label so I can use it in other forms.
But when I try to convert the label to int32 the label always seems to be empty. I think its because of where the function is placed in my code.
See:
private void Loginbtn_Click(object sender, EventArgs e)
{
var LoginFunction = new LoginFunction();
var DataTable = new DataTable();
DataTable = LoginFunction.Login(Usernametxt.Text.Trim(), Passwordtxt.Text.Trim());
int UserID = Convert.ToInt32(DataTable.Rows[0]["USER_ID"]);
if (DataTable.Rows.Count == 1)
{
CalculatorMain calculatorMain = new CalculatorMain();
MainMenu mainMenu = new MainMenu();
UserIDlbl.Text = Convert.ToString(UserID);
MessageBox.Show("ID = " + UserID);
this.Hide();
mainMenu.Show();
}
else
{
MessageBox.Show("You entered the wrong username or password");
}
}
public int GetUserID()
{
int UserID;
if (Int32.TryParse(UserIDlbl.Text, out UserID))
{
UserID = Convert.ToInt32(UserIDlbl.Text);
}
else
{
MessageBox.Show("Error, Label for UserID could not be parsed");
}
return UserID;
}
I'm not sure where else I can put this function to get it to work.
Here is the code to call the function which is used in a separate form.
private void WorkoutHistoryForm_Load(object sender, EventArgs e)
{
Login login = new Login();
int UserId = login.GetUserID();
this.sETSTableAdapter.Fill(this.gymDataSet.SETS, UserId);
}
I keep thinking there must be a better way to do this instead of storing the UserID in a label but I'm not sure how.
I would create a public class with a public field to store the UserID.
For example. let's say you have the UserID in an int variable as you have described. Now let's say you have created a public static class called Common defined with a public static field of type int called ID.
You can now store the UserID in the static field of the class:
Common.ID = UserID
Later, when you want to access the UserID from some other form, just do this:
string UserID = Common.ID
Easy peasey.
Of course, you don't need to do this in a separate class... your form itself is a class, and you can create your public field there, and call it like
Form1.UserID
Or whatever the name of your original form is where you captured the UserID...
When I write the code like the methods below my fields get initialized correctly and the application works fine.
private string username;
private string password;
public string Password
{
get { return password; }
set { password = value; }
}
public string Username
{
get { return username; }
set { username = value; }
}
public Authenticate()
{
this.username = "njabulo";
this.password = "12345";
}
Before writing it like this I had written the code in the following fashion and the fields didn't get initialized:
private string username;
private string password;
public string Password
{
get { return password; }
set { password = "njabulo"; }
}
public string Username
{
get { return username; }
set { username = "12345"; }
}
I would like to know what exactly is causing the error in the second method. I think the value on the set property stands for anything that may be thrown at the property and I am giving it an actual value.
There is no reason to Set to a literal value, you may as well do
get { return "njabulo"; }
If you are using C# 6 then you can initialize like:
public string Password {get; set;} = "njabulo";
Then it will initialize, but not always stay that value if you set it later.
When you define a property, with getter or setter, it means that the code for getter or setter only execute when any of these actions occurred.
In the second example you haven't called the setter yet.and there is no reason to specify setter with a content value.
The first example is fine bcoz you have done the followings
1.Defined properties with back end fields.
2.initialised back end fields
But in the second one you haven't made initialisation.
The purpose of set is to allow setting the value of that property, like this:
var x = new WhateverYourClassIsNamed();
x.Username = "ABC";
You would normally write the property like this:
public string Username
{
get { return username; }
set { username = value; }
}
That way if someone calls
x.Username = "newusername";
then when the set method is called, value is "newusername"; That's how you can set a property on your class. You don't have to declare a variable named value. That automatically refers to whatever value is used when you call set.
If you do this:
set { username = "12345"; }
Then it doesn't matter what value you try to set. You could call
x.Username = "99999"
or any other value, but it's always going to set username to "12345".
Usually when we say "initialize" we mean values that are set when the class is first created. If that's what you had in mind you could do this:
private string username;
private string password = "12345"; //This set whenever you create
//a new instance of the class
public string Password
{
get { return password; }
set { password = value; }
}
public string Username
{
get { return username; }
set { username = value; }
}
or do as Crowcoder suggested,
public string Password {get; set;} = "12345";
That's a newer, more convenient syntax that does the same thing.
The correct initialization is the first method, or make it shorter using automatic property. The second method, before anybody call "set", your Password or Username is still null :
public string Password { get; set; }
public string Username { get; set; }
public Authenticate()
{
Username = "njabulo";
Password = "12345";
}
I add more because of your comments above (compare value), you can use it like this:
public class Authenticate
{
private string _password;
private string _username;
public Authenticate()
{
_password = "mypassword";
_username = "myusername";
}
public string Password
{
get { return _password; }
set
{
if (_password != value) // Compare it here
_password = value;
}
}
public string Username
{
get { return _username; }
set
{
if (_username != value) // Compare it here
_username = value;
}
}
}
when i try to set a specific Item in dataGrid , it changes all other item's values to that same value. I'm not sure if it's a bug or i done something wrong. Here is my code:
(Datagrid is in another window (Main window), so i called a function in that window to edit the value)
private void AAbutton1_Click(object sender, RoutedEventArgs e)
{
Account selected = new Account();
if (textBox2.Text != null)
selected.username = textBox2.Text;
if (textBox12.Text != null)
selected.password = textBox12.Text;
if (locationTxtBox2.Text != null)
selected.location = locationTxtBox2.Text;
MainWindow.Instance.editAccount(selected);
MainWindow.Instance.updateData();
MainWindow.Instance.needsSave = true;
}
And here is the function in the main window:
public void editAccount(Account acc)
{
Account acc2;
Account selected = (Account)dataGrid.SelectedItem;
acc2 = Manager.accounts.ElementAt(Manager.accounts.FindIndex(a=> a == selected));
acc2.username = acc.username;
acc2.password = acc.password;
acc2.location = acc.location;
}
I really couldn't find a solution for this problem.
And here is the Account class in case you need it:
public class Account
{
public String username { get; set; }
public String password { get; set; }
public String location { get; set; }
public Account(String username,String password, String location)
{
this.username = username;
this.password = password;
this.location = location;
}
public Account()
{
}
}
Just to mention , i use Mahapps.metro controls.
I was right! I read your mind.
This isn't a WPF question, a binding question, or a DataGrid question. It's a "how do references work in C#?" question. It's a good question.
On file load, you start with a list of encrypted Accounts, but in decryption, you copy all the decrypted properties of each one of the accounts into the same instance of Account, and add that one instance multiple times to the list. The decrypted ones are all the same instance. You start off OK, but then you go off the rails in DecryptAccounts().
Here's the bug:
public static void DecryptAccounts()
{
// Hmmm. What's he planning to do with this?
Account holder = new Account(null, null, null);
accounts.Clear();
foreach (Account acc in Encryptedaccounts)
{
// HERE IT IS. This is the same instance of holder on every
// iteration. After file load, every Account in accounts is the
// same object as every other.
// You need to create a new Account object for each account.
holder.username = Decrypt(acc.username, user.Decryptedpassword);
holder.password = Decrypt(acc.password, user.Decryptedpassword);
holder.location = Decrypt(acc.location, user.Decryptedpassword);
accounts.Add(holder);
}
}
public static void LoadFromFile()
{
if (File.Exists(Path.Combine(appdata, folder, file)))
{
Encryptedaccounts = JsonConvert.DeserializeObject<List<Account>>(File.ReadAllText(Path.Combine(appdata, folder, file)));
}
DecryptAccounts();
}
Here's the fix
Manager.cs
public Account DecryptAccount(Account acc)
{
return new Account {
username = Decrypt(acc.username, user.Decryptedpassword),
password = Decrypt(acc.password, user.Decryptedpassword),
location = Decrypt(acc.location, user.Decryptedpassword)
};
}
public static void DecryptAccounts()
{
accounts.Clear();
foreach (Account acc in Encryptedaccounts)
{
accounts.Add(DecryptAccount(acc));
}
}
// You've got the same issue here
private static void EncryptAccounts()
{
Encryptedaccounts.Clear();
foreach (Account acc in accounts)
{
Encryptedaccounts.Add(EncryptAccount(acc));
}
}
public Account EncryptAccount(Account acc)
{
return new Account {
username = Encrypt(acc.username, user.Decryptedpassword),
password = Encrypt(acc.password, user.Decryptedpassword),
location = Encrypt(acc.location, user.Decryptedpassword)
};
}
Some other issues here. Not bugs, but life will be easier if you do stuff the "proper WPF way":
Manager.accounts should be of type ObservableCollection<Account>. Then it will automatically notify the DataGrid whenever you add or remove items from it and you won't have to do this updateData() thing to manually refresh the grid all the time.
Manager and Account both ought to implement INotifyPropertyChanged and fire notifications on their properties when their values change. In C#6, this is very simple:
using System.Runtime.CompilerServices;
using System.ComponentModel;
// ... snip ...
public event PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
Then your properties look like this:
private String _username = null;
public String username {
get { return _username; }
set {
if (value != _username)
{
_username = value;
OnPropertyChanged();
}
}
}
When they do that, anything you bind them to in the UI will be notified whenever you change the values. You'll be able to set properties on the selected grid item and the UI will update without any grid refresh or anything -- it'll just know. Very convenient.
I need a Login function(login is just an example, any other frequently used method can be fine) which takes email and password as parameter and asks DB if there is such a user. If yes, it has to return customer_id(int), if no, it will return the message why login could not happen(ex:no such an email address).
I also do not wanna rewrite the login function everytime. I want to write it once in a common project which I can use in my every project and reuse it. But i am trying to find out the best practice for this. So far, i thought something like below, but the problem for me is that i cannot return customerID which i will get in codebehind in my projects(any other project) and open a session variable with it. I only can return strings in below structure. I also thought returning a Dic, but this also is wrong I guess because if bool(key) happens to be true, customerID is not a string(value). Can you help me please learning the correct way of using common functions with no need to think the returning messages and variables twice? Thanks a lot
public class UserFunctions
{
private enum Info
{
//thought of returning codes??
LoginSuccess = 401,
NoMatchPasswordEmail = 402,
InvalidEmail = 403,
};
public string TryLogin(string email, string password)
{
bool isValidEmail = Validation.ValidEmail(email);
if (isValidEmail == false)
{
return Result(Info.InvalidEmail);
// returning a message here
}
Customers customer = new Customers();
customer.email = email;
customer.password = password;
DataTable dtCustomer = customer.SelectExisting();
if (dtCustomer.Rows.Count > 0)
{
int customerID = int.Parse(dtCustomer.Rows[0]["CustomerID"].ToString());
return Result(Info.LoginSuccess);
// Here I cant return the customerID. I dont wanna open a session here because this function has no such a job. Its other projects button events job I guess
}
else
{
return Result(Info.NoMatchPasswordEmail);
}
}
private string Result(Info input)
{
switch (input)
{
case Info.NoMatchPasswordEmail:
return "Email ve şifre bilgisi uyuşmamaktadır";
case Info.InvalidEmail:
return "Geçerli bir email adresi girmelisiniz";
case Info.LoginSuccess:
return "Başarılı Login";
}
return "";
}
}
You may want to consider returning an instance of a custom class.
public class LoginResult
{
public Info Result { get; set; }
public int CustomerId { get; set;}
}
Modify your TryLogin method to return an instance of LoginResult.
Base your application flow on the result:
var loginResult = TryLogin(..., ...);
switch (loginResult.Result)
{
case Info.LoginSuccess:
var customerId = loginResult.CustomerId;
//do your duty
break;
case Info.NoMatchPasswordEmail:
//Yell at them
break;
...
}
You could try Creating an event and then the calling code can register to the event before attempting to login.
For example:
public class UserFunctions
{
private enum Info
{
LoginSuccess = 401,
NoMatchPasswordEmail = 402,
InvalidEmail = 403,
};
public delegate void LoginAttemptArgs(object sender, Info result, int CustomerID);//Define the delegate paramters to pass to the objects registered to the event.
public event LoginAttemptArgs LoginAttempt;//The event name and what delegate to use.
public void TryLogin(string email, string password)
{
bool isValidEmail = Validation.ValidEmail(email);
if (isValidEmail == false)
{
OnLoginAttempt(Info.InvalidEmail, -1);
}
Customers customer = new Customers();
customer.email = email;
customer.password = password;
DataTable dtCustomer = customer.SelectExisting();
if (dtCustomer.Rows.Count > 0)
{
int customerID = int.Parse(dtCustomer.Rows[0]["CustomerID"].ToString());
OnLoginAttempt(Info.LoginSuccess, customerID);
}
else
{
OnLoginAttempt(Info.NoMatchPasswordEmail, -1);
}
}
private void OnLoginAttempt(Info info, int CustomerID)
{
if (LoginAttempt != null)//If something has registered to this event
LoginAttempt(this, info, CustomerID);
}
}
I wouldn't compile a string to return, I would return the enum result and let the calling code do what it likes with the result. reading an enum is much quicker than parsing returned string.
Edit: Typos and i missed an event call... .Twice