Boolean value magically changed to false from ViewModel to View - c#

I need to validate two password fields. If they match then the credential has to be validated in the validation viewmodel. I set a bool value validPassword in the validation viewmodel and need to refer it in the view. Then do something in the view according to validPassword value. However, validPassword always is false when I refer it in the view even though it is true in the viewmodel.
ViewModel:
internal static bool validPassword;
public static bool CheckCredentials(string username, string password, string domain)
{
string userPrincipalName = username + "#" + domain + ".com";
try
{
using(var context = new PrincipalContext(ContextType.Domain, domain))
{
validPassword = true;
return context.ValidateCredentials(userPrincipalName, password);
}
}
catch // a bogus domain causes an LDAP error
{
errorsForPassword.Add("Invalid Login!");
validPassword = false;
return false;
}
}
Code behind the view:
private void PwBox_OnKeyDown(object sender, RoutedEventArgs e)
{
System.Windows.Controls.ToolTip toolTip = new System.Windows.Controls.ToolTip();
//PasswordBox passwordBox = sender as PasswordBox;
passwordAgain = PasswordAgainBox.Password;
if(string.IsNullOrEmpty(passwordAgain) || !string.Equals(passwordAgain, MiscParameterViewModel.password))
{
PwBoxBorder.BorderBrush = new SolidColorBrush(Colors.Red);
MiscParameterViewModel.nextButtonIsEnabled = false;
if(string.IsNullOrEmpty(passwordAgain))
{
toolTip.Content = "Please enter the password again!";
ToolTipService.SetToolTip(PasswordAgainBox, toolTip);
}
else if(!string.Equals(passwordAgain, MiscParameterViewModel.password))
{
toolTip.Content = "Passwords don't match!";
ToolTipService.SetToolTip(PasswordAgainBox, toolTip);
}
}
else
{
//ToolTipService.SetToolTip(PasswordAgainBox, null);
//PwBoxBorder.BorderBrush = new SolidColorBrush(Colors.Transparent);
_validationViewModel.Authenticate();
if(!ValidationViewModel.validPassword)
{
toolTip.Content = "Invalid password!";
ToolTipService.SetToolTip(PasswordBox, toolTip);
ToolTipService.SetToolTip(PasswordAgainBox, toolTip);
PwBoxBorder.BorderBrush = new SolidColorBrush(Colors.Red);
PwBoxAgainBorder.BorderBrush = new SolidColorBrush(Colors.Red);
}
else
{
ToolTipService.SetToolTip(PasswordBox, null);
ToolTipService.SetToolTip(PasswordAgainBox, null);
PwBoxBorder.BorderBrush = new SolidColorBrush(Colors.Transparent);
PwBoxAgainBorder.BorderBrush = new SolidColorBrush(Colors.Transparent);
}
}
}
Authenticate is an async method in the viewmodel and it calls CheckCredentials method.
Here is the Authenticate method:
public async void Authenticate()
{
MiscParameterViewModel.nextButtonIsEnabled = false;
NotifyPropertyChanged("NextButtonIsEnabled");
const string propertyKey = "Password";
bool isValid = false;
/* Call service asynchronously */
if(MiscParameterViewModel.servServiceLoginType == ServiceLoginTypes.Windows)
{
if(errorKeys.ContainsKey(propertyKey))
{
errorsForPassword.Clear();
errorKeys.TryRemove(propertyKey, out errorsForPassword);
/* Raise event to tell WPF to execute the GetErrors method */
RaiseErrorsChanged(propertyKey);
}
//if(string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(passwordAgain))
if(string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
{
errorsForPassword.Add("Login is required!");
errorKeys.TryAdd(propertyKey, errorsForPassword);
isValid = false;
}
else
{
isValid = await Task<bool>.Run(() =>
{
return CheckCredentials(username, password, domain);
})
.ConfigureAwait(false);
}
}

What's happening is that your Authenticate method is executing CheckCredentials on another thread, then returning control to your view. What this means is that you will (sometimes) get to this line:
if(!ValidationViewModel.validPassword)
before CheckCredentials has been called. You're seeing false because that's the default value for booleans - it hasn't been set yet.
You could fix this in a couple of different ways. You could return a Task from your authenticate method, and then call .Wait() on the task before checking validPassword.
Or you could simply remove the async/await from your Authenticate method and make it a synchronous method. Which is right depends on the rest of your application.
Edit: Here's my attempt at your authenticate method. I had to guess on some of the functionality you want.
public async Task<bool> Authenticate()
{
MiscParameterViewModel.nextButtonIsEnabled = false;
NotifyPropertyChanged("NextButtonIsEnabled");
const string propertyKey = "Password";
/* Call service asynchronously */
if(MiscParameterViewModel.servServiceLoginType == ServiceLoginTypes.Windows)
{
if(errorKeys.ContainsKey(propertyKey))
{
errorsForPassword.Clear();
errorKeys.TryRemove(propertyKey, out errorsForPassword);
/* Raise event to tell WPF to execute the GetErrors method */
RaiseErrorsChanged(propertyKey);
}
//if(string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password) || string.IsNullOrEmpty(passwordAgain))
if(string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
{
errorsForPassword.Add("Login is required!");
errorKeys.TryAdd(propertyKey, errorsForPassword);
return false;
}
else
{
return await Task<bool>.Factory.StartNew(() => CheckCredentials(username, password, domain));
}
}
return false;
}
Once you get the task back, you'll have to decide what to do with it. If you just call .Wait(), it will work, but you'll get the same problem you had where the GUI freezes while you're waiting.
You might want to use the .ContinueWith() method instead, which will be called once the task is complete, and then in there you can update your password box. You might need to marshall the changes back onto the GUI thread (ContinueWith will be on another thread) to set the password box's values - not sure without the complete solution. Hope that helps

Related

Multiple Tasks in parallel - One Section "one after another"

I have several tasks running the same method in parallel. For a specific part of this method. I want the tasks to go one after another (not parallel).
Background: In the specific Part, I open another Form, where the User enters a Password. I Don't want the User to enter the password for every single tasks. The first one should get saved in a global string and used by the other tasks.
private void S7_GetCPU()
{
//Some Stuff
if (CPUPassword != null)
{
EncryptedString pwd = new EncryptedString(CPUPassword);
this.CPU.SetPassword(pwd);
}
if (!this.CPU.PasswordValid)
{
CPUPassword = ((MainForm)mainform)
.ShowInputMessage("Enter Password for CPU"), true);
EncryptedString pwd = new EncryptedString(CPUPassword);
this.CPU.SetPassword(pwd);
}
//More Parallel-Stuff
}
I tried to put this part into a Invoke. The Input-Message opens only one time. But all other tasks freeze at that point, even after the first task has left the .invoke
private void S7_GetCPU()
{
//Some Stuff
this.Invoke(new System.Action(() =>
{
if (CPUPassword != null)
{
EncryptedString pwd = new EncryptedString(CPUPassword);
this.CPU.SetPassword(pwd);
}
if (!this.CPU.PasswordValid)
{
CPUPassword = ((MainForm)mainform)
.ShowInputMessage("Enter Password for CPU"), true);
EncryptedString pwd = new EncryptedString(CPUPassword);
this.CPU.SetPassword(pwd);
}
}));
//More Parallel-Stuff
}
Solved it by: lock
private static readonly object PWLock = new object();
private void S7_GetCPU()
{
//Some Stuff
lock(PWLock)
{
if (CPUPassword != null)
{
EncryptedString pwd = new EncryptedString(CPUPassword);
this.CPU.SetPassword(pwd);
}
if (!this.CPU.PasswordValid)
{
CPUPassword = ((MainForm)mainform)
.ShowInputMessage("Enter Password for CPU"), true);
EncryptedString pwd = new EncryptedString(CPUPassword);
this.CPU.SetPassword(pwd);
}
}));
//More Parallel-Stuff
}

Call function from method in one classes in another class

Hello so i got very easy function to download files from FTP. Looks like this:
//Download files from FTP, return true of false if succed
public static bool DownloadFileFromFTP( string ip, string RemoteFilePath, string LocalFilePath, string username, string password)
{
try
{
FtpClient client = new FtpClient(ip);
client.Credentials = new NetworkCredential(username, password);
client.Connect();
ProgressBar progressBar;
progressBar = new ProgressBar();
Progress<double> progress = new Progress<double>(x => {
if (x > 0)
{
progressBar.Report((double)x / 100);
}
});
bool succes = client.DownloadFile(LocalFilePath, RemoteFilePath, FtpLocalExists.Overwrite, FluentFTP.FtpVerify.Retry, progress);
if(succes == true)
{
succes = true;
}
else
{
succes = false;
}
client.Disconnect();
progressBar.Dispose();
return succes;
}
catch(Exception e)
{
MessageBox.Show(e.ToString());
return false;
}
}
And this method is in one class and i call it in another class like this:
Functions_General.DownloadFileFromFTP("192.168.240.86", "Ultra_Script/path", #"C:\Windows\Temp\Adobe_Reader.exe", "username", "password");
Everything works as expected. But the function itself have progressbar inside it and its disposing after finished downloading with this:
progressBar.Dispose();
But there comes the problem i need to dispose it in class where im calling the method is there any option how can i achieve that?
I need to have 3 synchronous progress bars and dispose them after all of 3 downloads are complete.
Thanks,

wpf - LDAP always returns false when validating

My login window uses LDAP to authenticate users. However, when validating, it always returns false.
Here is the code for validation which I got from CodeProject:
public bool fnValidateUser()
{
bool validation;
try
{
LdapConnection lcon = new LdapConnection
(new LdapDirectoryIdentifier((string)null, false, false));
NetworkCredential nc = new NetworkCredential(Environment.UserName,
txtPassword.SecurePassword, Environment.UserDomainName);
lcon.Credential = nc;
lcon.AuthType = AuthType.Negotiate;
// user has authenticated at this point,
// as the credentials were used to login to the dc.
lcon.Bind(nc);
validation = true;
}
catch (LdapException)
{
validation = false;
}
return validation;
}
txtPassword.SecurePassword is the PasswordBox. When I enter my password/pin and hit login, it displays the MessageBox for whenever validation is false.
What am I doing wrong?
UPDATE: The exception indicates "The LDAP Server is Unavailable", at this line lcon.Bind(nc);
You can try this sample piece of code.
// the username and password to authenticate
const string domain = "OU=Organization,DC=mydomain,DC=com";
string password = "mypass";
string userName = "myuser";
// define your connection
LdapConnection ldapConnection = new LdapConnection("ldap.mydomain.com:389");
try
{
// authenticate the username and password
using (ldapConnection)
{
// pass in the network creds, and the domain.
var networkCredential = new NetworkCredential(username, password, domain);
// if we're using unsecured port 389, set to false. If using port 636, set this to true.
ldapConnection.SessionOptions.SecureSocketLayer = false;
// since this is an internal application, just accept the certificate either way
ldapConnection.SessionOptions.VerifyServerCertificate += delegate { return true; };
// to force NTLM\Kerberos use AuthType.Negotiate, for non-TLS and unsecured, just use AuthType.Basic
ldapConnection.AuthType = AuthType.Basic;
// authenticate the user
ldapConnection.Bind(networkCredential);
}
catch (LdapException ldapException)
{
//Authentication failed, exception will dictate why
}
}
I went ahead and found another approach for this, without using LDAP.
PrincipalContext adContext = new PrincipalContext(ContextType.Machine);
private async void btnLogin_Click(object sender, RoutedEventArgs e)
{
try
{
using (adContext)
{
if (adContext.ValidateCredentials(txtUsername.Text, txtPassword.Password))
{
MainWindow main = new MainWindow();
main.Show();
main.txtLoggedInUser.Text = UserPrincipal.Current.DisplayName;
this.Close();
}
else
{
MessageBox.Show("Incorrect Username or Password!");
}
}
}
catch(Exception ex)
{
var exceptionDialog = new MessageDialog
{
Message = { Text = ex.ToString() }
};
await DialogHost.Show(exceptionDialog, "RootDialog");
}
}

Nested Asynchronous function in Silverlight

I am trying to call a nested Asynchronous function but I am not getting the required data.
Since I am using a wcf service with Silverlight I can only use Asynchronous functions.
In my code I am saving a set of rows containing userdata. Before I save it I need to check the username is unique. Now I only need to find out the first one and then break out of loop and show a message to the user.for simplicity sake, I have stripped the function of all the extra data and this is how it looks
private void SaveUsers(bool CloseForm)
{
ObservableCollection<User> _UpdatedUsers = new ObservableCollection<User>();
DatabaseServiceLocal _dataService = new DatabaseServiceLocal(Database);
foreach (UserViewModel _User in _AllUsers)
{
//bool success = _dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
if (_User.Dirty && !_User.IsBlank)
{
_dataService.CheckIsUserNameUnique += (s, e) =>
{
if (e.IsUnique)
_UpdatedUsers.Add(_User.SaveAsUser());
else
{
_UpdatedUsers = new ObservableCollection<User>();
csaMessageBox.Show(string.Format("Username {0} is not allowed as it already exists in the system. Please choose a different username.", ""), null);
return;
}
};
_dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
}
_dataService.UpdateStaffAndUsersCompleted += (s, e) =>
{
BusyIndicator = false;
if (e.Success)
{
}
if (CloseForm)
ReturnToHomePage();
else
{
LoadUsers();
OnUsersSaved();
}
}
BusyIndicator = true;
BusyMessage = "Saving...";
_dataService.UpdateUsers(Database.CurrentProject.ProjectID, Database.CurrentClient.ClientID, _UpdatedUsers, _DeletedProjectUsers);
}
In this case I am trying to find if the username is unique,show user a message and return.
Obviously it's not as simple as that.I have tried a couple more different ways but it didn't work. How do I get this working?
I think you can make your life easier by adding a couple of helper functions. The first one is an asynchronous function that checks whether a user is unique. You may need to add some code to set tcs.SetException if there is an error.
private Task<bool> IsUserUniqueAsync(UserViewModel user, DatabaseServiceLocal dataService)
{
var tcs = new TaskCompletionSource<bool>();
dataService.CheckIsUserNameUnique += (s, e) =>
{
tcs.SetResult(e.IsUnique);
};
dataService.IsUserNameUnique(user.UserName, user.UserID, Database.CurrentClient.ClientID);
return tcs.Task;
}
The second one updates all the users asynchrnously
public Task<bool> UpdateUsersAsync(ObservableCollection<User> updatedUsers, DatabaseServiceLocal dataService)
{
var tcs = new TaskCompletionSource<bool>();
BusyIndicator = true;
BusyMessage = "Saving...";
dataService.UpdateStaffAndUsersCompleted += (s, e) =>
{
BusyIndicator = false;
tcs.SetResult(e.Success);
};
dataService.UpdateUsers(Database.CurrentProject.ProjectID, Database.CurrentClient.ClientID, updatedUsers, _DeletedProjectUsers);
return tcs.Task;
}
Then your SaveUsers method becomes a bit simpler.
private async void SaveUsers(bool CloseForm)
{
ObservableCollection<User> _UpdatedUsers = new ObservableCollection<User>();
DatabaseServiceLocal _dataService = new DatabaseServiceLocal(Database);
Dictionary<Task<bool>, User> tasks = new Dictionary<Task<bool>, User>();
// start all tasks in parallel
foreach (UserViewModel _User in _AllUsers)
{
if (_User.Dirty && !_User.IsBlank)
{
tasks.Add(IsUserUniqueAsync(_User, _dataService), _User);
}
}
// process each task as it completes
while(tasks.Count() > 0 )
{
var task = await Task.WhenAny(tasks.Keys.ToArray());
if(task.Result)
{
_UpdatedUsers.Add(_User.SaveAsUser());
}
else
{
MessageBox.Show(string.Format("Username {0} is not allowed as it already exists in the system. Please choose a different username.", ""), null);
return;
}
tasks.Remove(task);
}
if( await UpdateUsersAsync(_UpdatedUsers, _dataService))
{
if (CloseForm)
ReturnToHomePage();
else
{
LoadUsers();
OnUsersSaved();
}
}
}
Your code would more or less look like this.
ObservableCollection<User> _UpdatedUsers = new ObservableCollection<User>();
int _verifiedUsersCount = 0;
DatabaseServiceLocal _dataService = new DatabaseServiceLocal(Database);
//Verify unique users
private void SaveUsers(bool CloseForm)
{
_dataService.CheckIsUserNameUnique += CheckIsUserNameUnique;
foreach (UserViewModel _User in _AllUsers)
{
//bool success = _dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
if (_User.Dirty && !_User.IsBlank)
{
_dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
}
}
}
//Store verified users to save
private void CheckIsUserNameUnique(object s, CheckIsUserNameUniqueEventArgs e)
{
if (e.IsUnique)
_UpdatedUsers.Add(_User.SaveAsUser());
else
{
csaMessageBox.Show(string.Format("Username {0} is not allowed as it already exists in the system. Please choose a different username.", ""), null);
}
verifiedUsersCount++;
//Call after all the users have been verified for uniqueness
if (_AllUsers.Count() == verifiedUsersCount)
{
OnUniqueUserVerifyComplete();
}
}
//Save verified users
private void OnUniqueUserVerifyComplete()
{
//No unique users
if (_UpdatedUsers.Count < 1) { return; }
_dataService.UpdateStaffAndUsersCompleted += (s, e) =>
{
BusyIndicator = false;
if (e.Success)
{
}
if (CloseForm)
ReturnToHomePage();
else
{
LoadUsers();
OnUsersSaved();
}
};
BusyIndicator = true;
BusyMessage = "Saving...";
_dataService.UpdateUsers(Database.CurrentProject.ProjectID, Database.CurrentClient.ClientID, _UpdatedUsers, _DeletedProjectUsers);
}

Login using WCF service application on a asp.net web application

I'm currently developing a dating site for a school project, and I'mm currently trying to make a log in feature for it. We are not supposed to use the automatic register and login feature.
Any contact we have with the database should go through the WCF service application. I know how to implement it without using the WCF, but I need to use it now, and I can't find this on Google after searching .
public bool login(string UserName, string PassWord, bool isActive = true) {
try {
DALDataContext db = new DALDataContext();
var qry = from m in db.tblUsers
where m.userName == UserName && m.password == PassWord && m.isActive == isActive
select m;
if (qry.Count() > 0) {
return true;
} else {
return false;
}
}
catch (Exception) {
return false;
}
}
That's how I made it, so this should work if I implement it in my web application
like this:
ServiceReference1.Service1Client obj = new ServiceReference1.Service1Client();
protected void btnLoginUser_Click1(object sender, EventArgs e) {
try {
string UserName = txtUserName.Text;
string PassWord = txtPassWord.Text;
obj.login(UserName, PassWord);
if (true) {
Session["me"] = UserName;
Response.Redirect("~/MyProfile.aspx");
}
}
catch (Exception){
}
}
I've been working with this for hours, the register part of this works... so I'm doing something really wrong or something. I'm using Visual Studio 2010 and SQL Server 2008 R2.
[SOLVED]
this is how i solved it
protected void btnLoginUser_Click1(object sender, EventArgs e)
{
try
{
string UserName = txtUserName.Text;
string PassWord = txtPassWord.Text;
bool isActive = true;
if (obj.login(UserName, PassWord, isActive))
{
Session["me"] = UserName;
Response.Redirect("~/MyProfile.aspx");
}
else
{
lblErr.Text = "fail";
}
}
catch (Exception)
{
}
}
}
}
You are ignoring the return value of your login method:
obj.login(UserName, PassWord); // <-- returns true/false.
if (true) // <-- Why?
{
...
Did you mean to do
if (obj.login(UserName, PassWord))
{
Session["me"] = UserName;
Response.Redirect("~/MyProfile.aspx");
} ...
Suggest to return user from WCF service by name, like:
public tblUser login(string UserName);
In the client side you can retrieve user by name:
var user = obj.login(UserName);
if (user != null && user.password == txtPassWord.Text)
DoLogin();
else
ShowError();

Categories