Select data from SQL Server in WPF app - c#

Having problems with accessing what is inside my list in a wpf application of a mafia game I am creating.
Basically I read from SQL Server 2016, then add it to my user collection list. Later when I use my list in a display, they all are there.
However the moment I use a foreach to loop through it to set a temp user equal to a found username, it only finds hard coded users and not ones added using the data read from SQL Server. Need help.
SQL Server read code:
using (connect = new SqlConnection(connetionString))
{
connect.Open();
string readString = "select * from Users";
SqlCommand readCommand = new SqlCommand(readString, connect);
using (SqlDataReader dataRead = readCommand.ExecuteReader())
{
if (dataRead != null)
{
while (dataRead.Read())
{
tempEmail = dataRead["Email"].ToString();
tempName = dataRead["Name"].ToString();
UserCollection.addUser(tempEmail, tempName);
}
}
}
connect.Close();
}
UserCollection relevant parts
private static List<User> UserList = new List<User>();
// add a user
public static void addUser(string email, string name)
{
UserList.Add(new User(email, name, 0, "unset", false, false, false, false, false, false,
false, "", false, false, false, 0, 0));
}
//return list of users for use elsewhere
public static List<User> ReturnUserList()
{
return UserList;
}
Use of a list to set tempPlayer in a wpf window
PlayersList = UserCollection.ReturnUserList();
// tempPlayer = UserCollection.ReturnAUser(sessionUser);
foreach (var element in PlayersList)
{
if (element.UserName == sessionUser)
{
tempPlayer = element;
}
}
Example of code where the list works.
// set listing of current players
ListOfPlayers = UserCollection.ReturnUserList();
var tempList = from player in ListOfPlayers
where player.UserBlocked == false
select new
{
Name = player.UserName,
Email = player.UserEmail,
};
this.PlayerListBox.ItemsSource = tempList;
hard coded User add that works fine and can be found by foreach statement from my app.xaml.cs
UserCollection.addUser("g", "Tom");

Firstly, is there a reason why you need a static method to add users to a collection? Even if you need access to the list via a static accessor, you are better having a static property on the same class which you're using to read the DB
The following snippet should hopefully be of some help.
public class UserManagement {
//Static property
private static List<User> _users;
public static List<User> Users {
get {
if (_users == null) {
_user = new List<User>();
}
return _users;
}
set { }
}
//Static load method must be called before accessing Users
public static void LoadDBUsers() {
using (SqlConnection connection = new SqlConnection(connetionString)) {
connection.Open();
string readString = "select * from Users";
using (SqlCommand command = new SqlCommand(readString, connection)) {
using (SqlDataReader reader = command.ExecuteReader()) {
while (reader.Read()) {
String tempEmail = reader["Email"].ToString();
String tempName = reader["Name"].ToString();
User user = new User(tempEmail, tempName, 0, "unset", false, false, false, false, false, false, false, "", false, false, false, 0, 0));
users.Add(user);
}
}
}
}
}
}
To use from another class :
UserManagement.LoadDBUsers();
var dbUsers = UserManagement.Users;
If you have another list of users (say from a file), you could add a loader method to your class which will handle that for you.
If at some point you need to clear down the list of users, you can simply set it to a new instance...
UserManagement.Users = new List<User>();
A slightly better way to do this would be to remove the static property Users first, change the method definition to return a List<User> from the LoadDBUsers method - eg.
public static List<User> LoadDBUsers() {
List<User> Users = new List<User>();
//Handle the database logic as in the previous example..
//Then at the end of the method..
return Users;
}
and call as follows
List<User> dbUsers = UserManagement.LoadDBUsers();
Using the latter approach, you don't need to worry about multiple locations in your code maintaining a static property. Just call and assign it to a variable.
It also has the advantage that you will always get the most current list of users from the DB without having to clear down and reload the list before you access it from the static property.
An added advantage of not using a global static property is that it can avoid potential memory issues. Static properties can be difficult to dispose by the garbage collector if a reference to them is held open.
With instance variables, it's quite obvious when one goes out of scope and is not referenced anymore, but with static variables, the reference is sometimes not disposed until the program ends.
In many cases, this isn't an issue, but in larger systems it can be a pain to debug.

tempEmail = dataRead["Email"].ToString();
tempName = dataRead["Name"].ToString();
tempEmail,tempName you are declare above on
using (connect = new SqlConnection(connetionString))
the tempEmail and tempName are reference type so, if loop it's first record add after second time loop tempName and tempEmail values update also previously added so,because it's also pointing same memory. so the data's are duplicate record list so, the users cannot add in user properly.
so, you can change your code
var tempEmail = dataRead["Email"].ToString();
var tempName = dataRead["Name"].ToString();
and before tempEmail,tempName remove the declaration before using statement.
I Hope this is Helpful for you.

I believe your while loop was causing the issue. Since "using" was in effect, the global, assumed, variables "tempEmail" & "tempName" remained null. I tested the code using MySql on my end and this solution was effective.
private List<User> PlayersList;
public Tester()
{
using (SqlConnection connect = new SqlConnection(connectionString))
{
connect.Open();
string readString = "select * from user";
SqlCommand readCommand = new SqlCommand(readString, connect);
using (SqlDataReader dataRead = readCommand.ExecuteReader())
{
if (dataRead != null)
{
while (dataRead.Read())
{
string tempEmail = dataRead["Email"].ToString();
string tempName = dataRead["Name"].ToString();
UserCollection.addUser(tempEmail, tempName);
}
}
}
connect.Close();
}
PlayersList = UserCollection.ReturnUserList();
}
public class User
{
public string email;
public string name;
// A constructor that takes parameter to set the properties
public User(string e, string n)
{
email = e;
name = n;
}
}
public static class UserCollection
{
private static List<User> UserList = new List<User>();
// add a user
public static void addUser(string email, string name)
{
UserList.Add(new User(email, name));
}
//return list of users for use elsewhere
public static List<User> ReturnUserList()
{
return UserList;
}
}
This is the area of concern.
while (dataRead.Read())
{
//Set local variable during while loop
string tempEmail = dataRead["Email"].ToString();
string tempName = dataRead["Name"].ToString();
UserCollection.addUser(tempEmail, tempName);
}

Related

Access Modifiers - Should be loaded only once

Can We prevent the following from loading more than once in my application. ie any other alternative than this?
public IEnumerable<User> users()
{
var users = Userlist();
return users.ToList();
}
public static List<User> Userlist()
{
string strSQL = "";
List<User> users = new List<User>();
strSQL = "select USERID,USERNAME,PASSWORD from USERS";
//if (Userlist().Count > 0)
//{
// return Userlist();
//}
//else
//{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["conn"].ConnectionString))
{
using (var command = new SqlCommand(strSQL, connection))
{
connection.Open();
using (var dataReader = command.ExecuteReader())
{
while (dataReader.Read())
{
users.Add(new User { Id = Convert.ToInt32(dataReader["USERID"]), user = dataReader["USERNAME"].ToString(), password = Decrypt(dataReader["PASSWORD"].ToString()), estatus = true, RememberMe = true });
}
}
}
}
return users;
// }
}
I just wanted the solution to be like the commented part(which does not work here).
EDIT : I just wanted to avoid unnecessary database calls.
Thanks in Advance!
The usual trick is to lazily load them. You could just use a Lazy<T>, but a double-checked simple field works too:
static List<Foo> fetched;
static readonly object syncLock = new object(); // because: threading
public static List<Foo> Whatever {
get {
var tmp = fetched;
if(tmp != null) return tmp;
lock(syncLock) {
tmp = fetched;
if(tmp != null) return tmp; // double-checked lock
return fetched = GetTheActualData();
}
}
}
private static List<Foo> GetTheActualData() {...}
Additional thoughts:
storing passwords is never a good idea
List<T> is mutable; you should make sure people can't change the list or the items in the list if you are storing it statically
what do you do when the data changes at the database? how does it update?
You can also use caching for this.
The idea is that, the List<Users> will be cached, and any time when applications asks for the user list, we return it from the cache, and avoiding the database hit thereof.
A sample implementation could be something like this. Suggest to read more about caching, as there are many aspects that needs to taken care like, when the cache will expire, how it will get invalidate if new users are entered in database etc.
public List<User> Userlist()
{
ObjectCache cache = MemoryCache.Default;
var users = cache["users"];
if (users == null)
{
CacheItemPolicy policy = new CacheItemPolicy();
//For dmonstration, I used cache expring after 1 day
//Set the cache policy as per your need
policy.AbsoluteExpiration = DateTime.Now.AddDays(1);
// Fetch the users here from database
List<User> userList = GetUsersFromDatabase();
//Set the users in the cache
cache.Set("users", userList, policy);
}
return cache["users"] as List<User>;
}
private static List<User> GetUsersFromDatabase()
{
string strSQL = "";
List<User> users = new List<User>();
strSQL = "select USERID,USERNAME,PASSWORD from USERS";
//if (Userlist().Count > 0)
//{
// return Userlist();
//}
//else
//{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["conn"].ConnectionString))
{
using (var command = new SqlCommand(strSQL, connection))
{
connection.Open();
using (var dataReader = command.ExecuteReader())
{
while (dataReader.Read())
{
users.Add(new User { Id = Convert.ToInt32(dataReader["USERID"]), user = dataReader["USERNAME"].ToString(), password = Decrypt(dataReader["PASSWORD"].ToString()), estatus = true, RememberMe = true });
}
}
}
}
return users;
}
Use Lazy, it is thread safe. Lazy
private Lazy<IEnumerable<User>> users = new Lazy<IEnumerable<User>>(Userlist);
public Lazy<IEnumerable<User>> Users
{
get
{
return this.users;
}
}
public static IEnumerable<User> Userlist()
{
string strSQL = "";
List<User> users = new List<User>();
strSQL = "select USERID,USERNAME,PASSWORD from USERS";
//if (Userlist().Count > 0)
//{
// return Userlist();
//}
//else
//{
using (var connection = new SqlConnection(ConfigurationManager.ConnectionStrings["conn"].ConnectionString))
{
using (var command = new SqlCommand(strSQL, connection))
{
connection.Open();
using (var dataReader = command.ExecuteReader())
{
while (dataReader.Read())
{
users.Add(new User { Id = Convert.ToInt32(dataReader["USERID"]), user = dataReader["USERNAME"].ToString(), password = Decrypt(dataReader["PASSWORD"].ToString()), estatus = true, RememberMe = true });
}
}
}
}
return users;
// }
}

Parsing excel .xls database into sql server database

I have asp.net mvc4 project, where have database with students, also have old database in .xls format and I need to migrate all values from old database into new one sql server database. In my mvc project I have membership controller which include method for Register new student. Also I'm write console application which parse .xls table and insert all values into my new database via Register method.
Console application:
static void Main(string[] args)
{
string con = #"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\MigrateExelSql\Include\TestDb.xlsx; Extended Properties=Excel 12.0;";
MembershipController mc = new MembershipController();
Student student = new Student();
student.Username = null;
student.Password = "password";
student.Email = null;
student.EntryYear = 2014;
student.PassportNumber = 0;
student.IsApproved = true;
student.PasswordFailuresSinceLastSuccess = 0;
student.IsLockedOut = false;
using(OleDbConnection connection = new OleDbConnection(con))
{
connection.Open();
OleDbCommand command = new OleDbCommand("select * from [Sheet1$]", connection);
using(OleDbDataReader dr = command.ExecuteReader())
{
while(dr.Read())
{
string row1Col0 = dr[0].ToString();
Console.WriteLine(row1Col0);
string row1Col1 = dr[1].ToString();
Console.WriteLine(row1Col1);
Console.WriteLine();
student.Username = row1Col0;
student.Email = row1Col1;
try
{
mc.Register(student);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}
Console.ReadKey();
}
Register method
public static MembershipCreateStatus Register(string Username, string Password, string Email, bool IsApproved, string FirstName, string LastName)
{
MembershipCreateStatus CreateStatus;
System.Web.Security.Membership.CreateUser(Username, Password, Email, null, null, IsApproved, null, out CreateStatus);
if (CreateStatus == MembershipCreateStatus.Success)
{
using (UniversityContext Context = new UniversityContext(ConfigurationManager.ConnectionStrings[0].ConnectionString))
{
Student User = Context.Students.FirstOrDefault(Usr => Usr.Username == Username);
User.FirstName = FirstName;
User.LastName = LastName;
Context.SaveChanges();
}
if (IsApproved)
{
FormsAuthentication.SetAuthCookie(Username, false);
}
}
return CreateStatus;
}
ActionResult POST
public ActionResult Register(Student student)
{
Register(student.Username, student.Password, student.Email, true, student.FirstName, student.LastName);
return RedirectToAction("Index", "Membership");
}
Everything work fine when I try to add students from web application, but when I try to add from my parsed database it was get the error on the next line
System.Web.Security.Membership.CreateUser(Username, Password, Email, null, null, IsApproved, null, out CreateStatus);
in my Register method, that invalidAnswer. I'm change null to "123456789", then next error will be invalidQuestion, then I'm also change from null to "123456789". And after this it's tell me that my invalidPassword. Also I'm added next line into my membership provider's line in my web.config requiresQuestionAndAnswer="false".
I have no idea why it's not working. Does anybody have any ideas?
Whenever I'm required to do anything like import data from spreadsheets like this simply write an Importer console app in my solution. I also use LINQ to CSV which you can get from Nuget and its a really useful tool to use.
It allows you to read in the data from your spreadsheet into the relevant class objects, and from there once you have validated each object you can simply create new objects in your Database using your Data Layer.
Since xls (not xlsx) files are basically text files in which contents are separated by usually a tab character (or maybe some certain spercial charchters) a better approach would be to read all the lines in the file and store them in a list.
Then you can split each element at the time you are inserting them in your database. This can be easily done using a foreach loop like:
foreach (var i in xlsList) {
String s [] = i.Split('\t').ToArray(); // refer to your file
for (int j = 0; j < s.lenght; j++) {
Your SQL statement in here
}
}

Retrieve name of user from Active Directory

I am admittedly very new to AD. I have a dropdown list that I have bound with a list of members within our organization. My end goal is to find their manager name, but I'm starting with baby steps.
I've done enough searching to get the right result. I'm having a problem getting the right data (verified by using breakpoints etc) out of the result
private void cmbUserList_SelectedIndexChanged(object sender, EventArgs e)
{
var userName = cmbUserList.SelectedValue.ToString();
DirectorySearcher search = new DirectorySearcher();
search.Filter = String.Format("(cn={0})", userName);
search.PropertiesToLoad.Add("givenName");
SearchResult result = search.FindOne();
if (result != null)
{
// For now I'm trying to just retrieve their name
lblManagerName.Text = result.GetDirectoryEntry().Name;
}
}
EDIT: I'm using .net version 4.0
Could someone point me towards retrieving the correct name, and then maybe even a link or resources to pull the manager name?
I think the problem with your code is you are using "(cn={0})", userName. You need to pass fully qualified name like
CN=Doe,John,OU=Users,OU=Headquarters,DC=company,DC=net
If you only have login ID, then the code below should work
DirectorySearcher directorySearcher = new DirectorySearcher("LDAP://RootDSE");
directorySearcher.Filter = "sAMAccountName=" + acctName;
directorySearcher.PropertiesToLoad.Add("manager");
SearchResult searchResult = directorySearcher.FindOne();
if (searchResult != null)
DirectoryEntry user = searchResult.GetDirectoryEntry();
Note that acctName is Windows login ID. If you want to play with AD and check out vearious properties and how they are stored, try dsquery and dsget command line tools. The command below will return a user record based on login id and will display contents of the manager field:
dsquery user domainroot -samid "loginid" | dsget user -samid -mgr
helper class and enum
public enum ActiveDirectoryObjectClass
{
Computer,
User,
Domain,
Group,
}
public static class ActiveDirectorySearcher
{
public static string GetCurrentDomainName()
{
string result;
using (Domain domain = Domain.GetCurrentDomain())
{
result = domain.Name;
}
return result;
}
public static IEnumerable<T> Select<T>(
ActiveDirectoryObjectClass activeDirectoryObjectClass,
Func<DirectoryEntry, ActiveDirectoryObjectClass, bool> condition,
Func<DirectoryEntry, T> selector
)
{
List<T> list = new List<T>();
using (Domain domain = Domain.GetCurrentDomain())
using (DirectoryEntry root = domain.GetDirectoryEntry())
{
string filter = string.Format("(objectClass={0})", activeDirectoryObjectClass);
using (DirectorySearcher searcher = new DirectorySearcher(filter))
{
searcher.SearchRoot = root;
searcher.SearchScope = SearchScope.Subtree;
using (SearchResultCollection result = searcher.FindAll())
{
foreach (SearchResult item in result)
{
using (DirectoryEntry entry = item.GetDirectoryEntry())
{
if (condition(entry, activeDirectoryObjectClass))
{
list.Add(selector(entry));
}
}
}
}
}
}
return list;
}
}
how to use
public IEnumerable<User> GetUsers()
{
return ActiveDirectorySearcher.Select(
ActiveDirectoryObjectClass.User,
(entry, adObjectClass) => string.Compare(entry.SchemaClassName, adObjectClass.ToString(), StringComparison.InvariantCultureIgnoreCase) == 0,
_ => new User
{
Name = _.Name.Substring(3),
Domain = ActiveDirectorySearcher.GetCurrentDomainName(),
});
}
Note: User in sample - custom class with properties Name, Domain, etc.
to find name and/or manager name:
if (sResult != null)
{
string userName = sResult.Properties["name"][0].ToString();
string managerDN = sResult.Properties["manager"][0].ToString();
DirectoryEntry man = new DirectoryEntry("LDAP://server_name/"+managerDN);
string managerName = man.Properties["name"][0].ToString();
}
server_name can be just domain component of FQDN i.e yourcompany.com, that way it will find catalog server on its own via DNS.
Edit:
I also recomend Active Directory Explorer from Sysinternals. It is great tool for exploring and understanding structure of AD

Changes in webservice are not reflected at the client?

I'm using a WCF-webservice and Linq-To-SQL to insert a new record.
However, in the webservice i'm setting two fields, CreatedBy and Created, but even if i use ref parameter(as suggested on MSDN) the changes are not reflected at the client. So when i debug the service the properties are set and the record is inserted correctly, but at the calling method the object's properties are still unset.
This will cause problems later, for example if i'll try to delete it i'll get following exception at db.SubmitChanges() since these columns are non-null:
System.Data.SqlTypes.SqlTypeException: SqlDateTime overflow. Must be
between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
Here's the insert method at the client(winforms application):
private void Add_Status()
{
using (var db = new ERP_ServiceClient())
{
var status = new Erp_ServiceReference.Status();
status.Name = this.txtStatusNameAdd.Text;
db.InsertStatus(status, this.IdUser);
statusBindingSource.Add(status);
}
this.txtStatusNameAdd.Text = "";
this.txtStatusNameAdd.Select();
}
This is the webservice method:
public void InsertStatus(ref Status status, int userID)
{
using (var db = new ERPDataContext())
{
status.CreatedBy = userID;
status.Created = DateTime.Now;
db.Status.InsertOnSubmit(status);
db.SubmitChanges();
}
}
What am i doing wrong? My wcf,winforms and linq-to-sql skills are rusty(that's why i've chosen them).
You can't pass by reference in a web service. You can return the value.
public Status InsertStatus(Status status, int userID)
{
using (var db = new ERPDataContext())
{
status.CreatedBy = userID;
status.Created = DateTime.Now;
db.Status.InsertOnSubmit(status);
db.SubmitChanges();
return status;
}
}
private void Add_Status()
{
using (var db = new ERP_ServiceClient())
{
var status = new Erp_ServiceReference.Status();
status.Name = this.txtStatusNameAdd.Text;
status = db.InsertStatus(status, this.IdUser);
statusBindingSource.Add(status);
}
this.txtStatusNameAdd.Text = "";
this.txtStatusNameAdd.Select();
}

How to test to see if mySql Database is working?

I am new to MySQL database, I am using Visual Studio C# to connect to my database. I have got a following select method. How can I run it to check if it is working?
EDITED The open and close connection methods
//Open connection to database
private bool OpenConnection()
{
try
{
// connection.open();
return true;
}
catch (MySqlException ex)
{
//When handling errors, your application's response based
//on the error number.
//The two most common error numbers when connecting are as follows:
//0: Cannot connect to server.
//1045: Invalid user name and/or password.
switch (ex.Number)
{
case 0:
MessageBox.Show("Cannot connect to server.");
break;
case 1045:
MessageBox.Show("Invalid username/password, please try again");
break;
}
return false;
}
}
//Close connection
private bool CloseConnection()
{
try
{
connection.Close();
return true;
}
catch (MySqlException ex)
{
MessageBox.Show(ex.Message);
return false;
}
}
Select method which is in the same class as the close and open connection as shown above
public List<string>[] Select()
{
string query = "SELECT * FROM Questions";
//Create a list to store the result
List<string>[] list = new List<string>[3];
list[0] = new List<string>();
list[1] = new List<string>();
list[2] = new List<string>();
list[3] = new List<string>();
list[4] = new List<string>();
list[5] = new List<string>();
list[6] = new List<string>();
list[7] = new List<string>();
//Open connection
if (this.OpenConnection() == true)
{
//Create Command
MySqlCommand cmd = new MySqlCommand(query, connection);
//Create a data reader and Execute the command
MySqlDataReader dataReader = cmd.ExecuteReader();
//Read the data and store them in the list
while (dataReader.Read())
{
list[0].Add(dataReader["id"] + "");
list[1].Add(dataReader["difficulty"] + "");
list[2].Add(dataReader["qustions"] + "");
list[3].Add(dataReader["c_answer"] + "");
list[4].Add(dataReader["choiceA"] + "");
list[5].Add(dataReader["choiceB"] + "");
list[6].Add(dataReader["choiceC"] + "");
list[7].Add(dataReader["choiceD"] + "");
}
//close Data Reader
dataReader.Close();
//close Connection
this.CloseConnection();
//return list to be displayed
return list;
}
else
{
return list;
}
}
This method is in a separate class which has got all the database connection settings. Now that I want to call this method from my main class to test it to see if it's working, how can I do this?
You should create an object instance of that DB class and then call the Select() method.
So, supposing that this DB class is named QuestionsDB you should write something like this:
QuestionDB questionDAL = new QuestionDB();
List<string>[] questions = questionDAL.Select();
However, before this, please correct this line
List<string>[] list = new List<string>[8]; // you need 8 lists for your db query
You could check if you have any record testing if the first list in your array list has more than zero elements.
if(questions[0].Count > 0)
... // you have read records.
However, said that, I will change your code adding a specific class for questions and using a list(of Question) instead of an array of list
So, for example, create a class like this
public class Question
{
public string ID;
public string Difficulty;
public string Question;
public string RightAnswer;
public string AnswerA;
public string AnswerB;
public string AnswerC;
public string AnswerD;
}
and change your select to return a List(of Question)
List<Question> list = new List<Question>;
......
while (dataReader.Read())
{
Question qst = new Question();
qst.ID = dataReader["id"] + "";
qst.Difficulty = dataReader["difficulty"] + "";
qst.Question = dataReader["qustions"] + "";
qst.RightAnswer = dataReader["c_answer"] + "";
qst.AnswerA = dataReader["choiceA"] + "";
qst.AnswerB = dataReader["choiceB"] + "";
qst.AnswerC = dataReader["choiceC"] + "";
qst.AnswerD = dataReader["choiceD"] + "";
list.Add(qst);
}
return list;
You can test whether the method works by writing a unit test for it. A good unit testing frame work is Nunit. Before you call this you must create and open a connection to the DB:
//Open connection
if (this.OpenConnection() == true)
{
as the other person said, you will want to fix the lists up.

Categories