having difficulty with a bit of code I have. I think variables are stuck inside the method I'm invoking and when I go to run that method again variables are no longer there.
Below is an example of my main:
public partial class Login : Form
{
public Login()
{
InitializeComponent();
}
sqlconnect sql = new sqlconnect();
public string pass;
public string user;
public void button1_Click(object sender, EventArgs e)
{
//Username and password textboxes send to public strings
user = textBox1.Text;
pass = textBox2.Text;
try
{
//try connecting to SQL database using SQL class
sql.GetSqlConnection();
sql.myConnection.Open();
this.Hide();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Here is the SQL connection class:
namespace NHS_Workshop_System
{
public class sqlconnect
{
public SqlConnection myConnection { get; set; }
Settings1 set = new Settings1();
Login var = new Login();
public SqlConnection GetSqlConnection()
{
if (myConnection == null)
myConnection = new SqlConnection("user id="+(var.user)+"; password="+(var.pass)+";server="+(set.SelectServer)+";Trusted_Connection="+(set.SelectContype)+";database="+(set.SelectDataBase)+"; connection timeout="+(set.Condrop)+"");
return myConnection;
}
}
}
So when I try to login it may work first time but if another form tries to run that method the username and password are missing. I'm not sure how to make the variables global so that every time I run the method it calls those details without fail. So the second time it uses sqlconnection on another form the ex message states that username and password are non existent. Is this a scoping issue if so can someone shed some light on how i might go about this maybe a new method of gaining access to an SQL server? Thank you tearing out my hair
Below is the answer for your question the way you have it now. But I strongly recommend you to think about what you are doing since your class logics doesn't seem to be very good. I see that your trying to implement Singleton which is good, but you can still make more instances of sqlconnect if you would like.
In your Login class, pass this instance of Login so the sqlconnector knows the user and pass that is declared here.
public partial class Login : Form
{
// Old style - sqlconnect sql = new sqlconnect();
sqlconnect sql;
public string pass; // These arent declared and wont be of use for your sql connect class
public string user;
public Login( String pass, String user )
{
this.pass = pass;
this.user = user;
// Now that we have a login with declared variables, pass it to the sqlconnect object
this.sql = new sqlconnect(this);
InitializeComponent();
}
Now in your sqlconnect class, before your Login variable was just empty. Now you have received an instance of it in your constructor that has it's variables set,
public class sqlconnect
{
public SqlConnection myConnection { get; set; }
Settings1 set = new Settings1();
// Here you maked a new one, use the existing instead from which this class is called.
// changed variable named from var to login..
Login login;
// *NEW* Constructor where you pass your login object
public sqlconnect(Login login)
{
this.login = login;
}
public SqlConnection GetSqlConnection()
{
if (myConnection == null)
myConnection = new SqlConnection("user id="+(login.user)+"; password="+(login.pass)+";server="+(set.SelectServer)+";Trusted_Connection="+(set.SelectContype)+";database="+(set.SelectDataBase)+"; connection timeout="+(set.Condrop)+"");
return myConnection;
}
}
Related
I have created a class UserInfo and I have set values on user login response, now I don't know how to access those values in another part of my app (another form).
Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MYCUSTOMAPP
{
class UserInfo
{
public string userId;
public string userType;
public string userName;
public string userUserName;
public string userPhone;
public string userIdCard;
}
}
Login (set values to class stings)
//....
SqlDataReader result = cmd.ExecuteReader();
if (result.HasRows)
{
while (result.Read())
{
UserInfo loggedUser = new UserInfo();
loggedUser.userId = result.GetValue(result.GetOrdinal("Id")).ToString();
loggedUser.userName = result.GetValue(result.GetOrdinal("Name")).ToString();
loggedUser.userType = result.GetValue(result.GetOrdinal("UserType")).ToString();
loggedUser.userUserName = result.GetValue(result.GetOrdinal("UserName")).ToString();
loggedUser.userPhone = result.GetValue(result.GetOrdinal("Phone")).ToString();
loggedUser.userIdCard = result.GetValue(result.GetOrdinal("IdCard")).ToString();
}
}
// the rest...
Question
Now let say I am in MainWindow form, how can I get value of userId for instance?
Update
Logic
User login
Store user data in class (or anything else that you might suggest)
Get those user data globally in my app so I don't need to call database each time I need user info (it will be presented already)
Update 2
My login function
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["MYCUSTOMAPPDatabaseString"].ConnectionString))
{
if (cn.State == ConnectionState.Closed)
cn.Open();
using (DataTable dt = new DataTable())
{
using (SqlCommand cmd = new SqlCommand("dbo.LoginUser", cn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#UserName", usernameBox.Text);
cmd.Parameters.AddWithValue("#Password", passwordBox.Text);
SqlDataReader result = cmd.ExecuteReader();
if (result.HasRows)
{
while (result.Read())
{
// Name of logged user from database (this is database response)
Console.WriteLine(result.GetValue(result.GetOrdinal("Name")));
// Add logged user info to `UserInfo` class
UserInfo loggedUser = new UserInfo();
loggedUser.userId = result.GetValue(result.GetOrdinal("Id")).ToString();
loggedUser.userName = result.GetValue(result.GetOrdinal("Name")).ToString();
loggedUser.userType = result.GetValue(result.GetOrdinal("UserType")).ToString();
loggedUser.userUserName = result.GetValue(result.GetOrdinal("UserName")).ToString();
loggedUser.userPhone = result.GetValue(result.GetOrdinal("Phone")).ToString();
loggedUser.userIdCard = result.GetValue(result.GetOrdinal("IdCard")).ToString();
MainWindow mainWindow = new MainWindow();
this.Hide();
mainWindow.ShowDialog();
Show();
}
}
else
{
cn.Close();
MessageBox.Show("Your credentials are not match!", "Error!", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
I think you can pass it as the parameters when you call another form's constructor, if you directly call that form. Like in this case : Communicate between two windows forms in C#
However, if you need to load it later on, you can either store it as user settings: https://www.youtube.com/watch?v=P432z8q9iVE. Or even more structural approach is store the data in database like MySQL, MSSQL, or another database that you can put when user click the call to action button.
Solved
I have changed my class to the following
class UserInfo
{
private string userId1;
private static string userType1;
private static string userName1;
private static string userUserName1;
private static string userPhone1;
private static string userIdCard1;
public string GetuserId()
{
return userId1;
}
public void SetuserId(string value)
{
userId1 = value;
}
public string GetuserType()
{
return userType1;
}
public void SetuserType(string value)
{
userType1 = value;
}
public string GetuserName()
{
return userName1;
}
public void SetuserName(string value)
{
userName1 = value;
}
public string GetuserUserName()
{
return userUserName1;
}
public void SetuserUserName(string value)
{
userUserName1 = value;
}
public string GetuserPhone()
{
return userPhone1;
}
public void SetuserPhone(string value)
{
userPhone1 = value;
}
public string GetuserIdCard()
{
return userIdCard1;
}
public void SetuserIdCard(string value)
{
userIdCard1 = value;
}
}
And changed my code in login response to:
while (result.Read())
{
UserInfo loggedUser = new UserInfo();
loggedUser.SetuserId(result.GetValue(result.GetOrdinal("Id")).ToString());
loggedUser.SetuserName(result.GetValue(result.GetOrdinal("Name")).ToString());
loggedUser.SetuserType(result.GetValue(result.GetOrdinal("UserType")).ToString());
loggedUser.SetuserUserName(result.GetValue(result.GetOrdinal("UserName")).ToString());
loggedUser.SetuserPhone(result.GetValue(result.GetOrdinal("Phone")).ToString());
loggedUser.SetuserIdCard(result.GetValue(result.GetOrdinal("IdCard")).ToString());
}
Now I can get my values in any form like:
UserInfo loggedUser = new UserInfo();
loggedUser.GetuserName(); // will return logged user name
How can i sign-out and redirect to the login page from a public static class?
I have tried the following but it does not stop page execution..
public static DatabaseNameEntities CreateEntitiesForSpecificDatabaseName(bool contextOwnsConnection = true)
{
string database_name = "";
try
{
database_name = System.Web.HttpContext.Current.Application["DB_NAME"].ToString();
}
catch (NullReferenceException)
{
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
}
//Initialize the SqlConnectionStringBuilder
//Initialize the EntityConnectionStringBuilder
//Create entity connection
EntityConnection connection = new EntityConnection(entityBuilder.ConnectionString);
return new DatabaseNameEntities(connection);
}
I have tried the following but it does not stop page execution..
That's because it's simply not the MVC way. It's also breaks the Single Responsibility Principle, that is, why would a method named CreateEntitiesForSpecificDatabaseName() know anything about MVC or logging out a user. The code you posted generally breaks this principle multiple times (application state, signing out a user).
Additionally, catching an exception you can prevent is also poor practice (or as the Lead Developer for the C# Compiler team called it, Boneheaded Exceptions).
Consider the following code.
public static ControllerBaseExtensions
{
private const string DBNAME = "DB_NAME";
public static bool TryGetDatabaseName(this ControllerBase instance,
out string DbName)
{
DbName = null;
var app = GetApp(instance);
var result = app.Any(k => k == DBNAME);
if (result)
{
DbName = instance.Application[DBNAME] as string;
result = DbName != null;
}
return result;
}
public static void SetDatabaseName(this ControllerBase instance,
string DbName)
{
var app = GetApp(instance);
app[DBNAME] = DbName;
}
private static HttpApplication GetApp(ControllerBase instance)
{
return instance.ControllerContext.HttpContext.Application;
}
}
public ActionResult MyMethod()
{
string DbName;
if (!this.TryGetDatabaseName(out DbName))
{
FormsAuthentication.SignOut();
// http://stackoverflow.com/questions/30509980
RedirectToAction("Login", "Account");
}
CreateEntitiesForSpecificDatabaseName(Dbname);
}
public static DatabaseNameEntities CreateEntitiesForSpecificDatabaseName(
string dbName,
bool contextOwnsConnection = true)
{
//Initialize the SqlConnectionStringBuilder
//Initialize the EntityConnectionStringBuilder
//Create entity connection
EntityConnection connection = new
EntityConnection(entityBuilder.ConnectionString);
return new DatabaseNameEntities(connection);
}
Does simply ie, no try or catch work as expected
public static DatabaseNameEntities CreateEntitiesForSpecificDatabaseName(bool contextOwnsConnection = true)
{
FormsAuthentication.SignOut();
FormsAuthentication.RedirectToLoginPage();
}
In my ASP.NET C# website I am attempting to use Sessions to allow users to log in and navigate throughout the secure pages while the session is valid. If for whatever reason they timeout or sign out, they are to be redirected to the landing page. Currently the site only allows one user to be logged in at a time. It seems apparent that the session information is being stored incorrectly, but I don't understand where or why this occurs. If you access the page using another browser, you can see the code pulling information out of the session (like the username) that it should not know.
I want to allow multiple valid users to be logged in simultaneously and have no adverse affect on each other while doing so. If you need further information than the code samples I post below, please ask.
My Login page:
//Login.ascx.cs
...
private void Login_Click(object sender, EventArgs e)
{
if (sender == null || e == null)
{
throw new ArgumentNullException("Null Exception: Login_Click");
}
User user = new User();
user.Login(_username.Text, _password.Text);
if (user.IsValid() && user.GetIsUser() != false)
{
user.Save();
Session["Username"] = _username.Text;
Response.Redirect("Secure/Default.aspx");
}
else
{
DisplayErrors(user._validationErrors);
}
_errors.Text = errorMessage;
}
The welcome page (first secure page a user sees)
private void Page_Load(object sender, System.EventArgs e)
{
Business.User user = new Business.User();
_labelUsername.Text = MySession.Current.Username;
_labelCompanyId.Text = MySession.Current.CompanyId;
redirectLogin = "../Default.aspx";
//redirect if any conditions fail for user validation.
if (sessionKey != MySession.GetSessionId() || (string)Session["Username"] != _labelUsername.Text)
{
Response.Redirect(redirectLogin);
}
else
{
Debug.WriteLine("Welcome SUCCESS: " + _labelUsername.Text);
Debug.WriteLine("Welcome " + sessionKey);
}
}
And finally the User page that includes SQL Query
public static string dataUsername;
public static string dataCompanyId;
private const string _getUserByUsernameQuery =
#"SELECT [User].[username], [Company].[name]
FROM [User] WITH (NOLOCK) INNER JOIN [Company] WITH (NOLOCK)
ON [User].[companyId] = [Company].[id]
WHERE [User].[username] = #username AND [User].[password] = #password";
private string _username;
private string _companyid;
public User(){}
public void Login (string username, string password)
{
using (SqlConnection connection = new SqlConnection(SQLConfiguration.ConnectionString))
{
SqlCommand command = new SqlCommand(_getUserByUsernameQuery, connection);
command.Parameters.AddWithValue("#username", username);
command.Parameters.AddWithValue("#password", password);
connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
if (reader.Read())
{
Username = Convert.ToString(reader["username"]);
CompanyId = Convert.ToString(reader["name"]);
dataUsername = Username;
dataCompanyId = CompanyId;
}
}
}
}
#region Properties
public string Username
{
get{ return _username; }
set{ _username = value;}
}
public string CompanyId
{
get{ return _companyid;}
set{ _companyid = value;}
}
#endregion
EDIT: In response to some of the questions:
//in the first accessed page for secure users, before 'Page_load'
public static string sessionKey
{
get
{
return MySession.GetSessionId();
}
}
...
//in my 'MySession' class
public static string GetSessionId()
{
return System.Web.HttpContext.Current.Session.SessionID;
}
See Static Classes and Static Class Members (C# Programming Guide)
A static constructor is only called one time, and a static class remains in memory for the lifetime of the application domain in which your program resides.
The code-
public static string GetSessionId()
{
return System.Web.HttpContext.Current.Session.SessionID;
}
Will return the same SessionID for the lifetime of the application.
Like other posters I would strongly recommend you use the ASP.NET built in membership providers rather than try and invent your own, this will be more secure, more widely understood and thus supported, easier to maintain and more extendable.
Just use ASP.NET Forms Authentication. I bet all anonymous users are sharing the same session object. You can hook it into your own authentication scheme if something already exists. (passwords in a database or file, for instance)
I am developing a series of processes in C# which reuse the same SQL code. Below is an example of a Class I created for the SQL Connection to my test database. Question: how to do I call the Class in my process? I have tried a couple of things however, I get the below errors
Errors:
SQLHelperCode.FirstConnect is a 'type' which is not valid in the given context.
Only Assignment, call, increment, decrement and new object expressions can be used as a statement
Class FirstConnect
public class FirstConnect
{
public FirstConnect()
{
SqlConnection conn;
string path = #"C:\Program Files (x86)\Microsoft SQL Server\MSSQL.1\MSSQL\Data";
const string dbName = "datadetail";
{
conn = new SqlConnection("user id=TestUser;" +
"server=TestData\\SQLEXPRESS;" +
"Trusted_Connection=yes;" +
"connection timeout=30");
try
{
conn.Open();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
Want to call the FirstConnect in this code:
protected override void OnBarUpdate()
{
accountName = Account.Name.ToString();
if (accountName == 'Test1234')
{
//Call FirstConnect here.
}
}
This line defines the class
public class FirstConnect
{
This line defines the constuctor
public FirstConnect()
{
The following will define a variable of type FirstConnect and then call the constructor to create it (I made it two lines to be explicit)
FirstConnect fc;
fc = new FirstConnect();
Typically you'd then want to have method that actually does something with the object
e.g.
SomeOtherObject varaibleName = fc.GetSomeData(accountName);
FirstConnect fc = new FirstConnect();
Not an answer but just a large comment...
When using classes that implement IDisposable like SqlConnection does, they should be used like so:
using (var conn = new SqlConnection("user id=TestUser;server=TestData\\SQLEXPRESS;Trusted_Connection=yes;connection timeout=30"))
{
//... do work ...
}
In the login page I am determining if the user is admin or not by the following code:
if (r.IsUserInRole(txtUserUsername.Text, "User") == true)
{
connection = ConfigurationManager.ConnectionStrings["GameHutDBEntities1"].ToString();
switch (new BusinessLayer.Users().ValidateLogin(txtUserUsername.Text, txtUserPassword.Text, connection))
{
case Helpers.LoginStatus.LoginSuccessful:
{
Response.Write("<Script> alert('Welcome to GameHut Admin Panel!')</Script>");
FormsAuthentication.RedirectFromLoginPage(txtUserUsername.Text, chkRemember.Checked);
break;
}
case Helpers.LoginStatus.Blocked:
{
Response.Write("<Script> alert('Account Blocked')</Script>");
break;
}
case Helpers.LoginStatus.Invalid:
{
Response.Write("<Script> alert('Invalid username or password')</Script>");
break;
}
}
}
In the connection class I am passing the connection string as follows:
public class ConnectionClass
{
public GameHutDBEntities Entities { get; set; }
public System.Data.IDbTransaction Transaction { get; set; }
public ConnectionClass()
{
this.Entities = new GameHutDBEntities();
}
public ConnectionClass(GameHutDBEntities _Entities)
{
this.Entities = _Entities;
}
public ConnectionClass(GameHutDBEntities _Entities, string conn)
{
this.Entities = _Entities;
this.Entities.Connection.ConnectionString = conn;
}
}
After the admin is logged and is redirect into another page the connection string is lost and the default connection string is set? Can someone tell me how to keep the connection string as long as the user logs out.
That's because you instantiate the class in the web form code behind and the instantiated object is lost when you switch to another page because of ASP.NET statelessness.
If you need to reuse the connection string save it in a session variable:
Session["conn"] = "connection string";
you will be able to reuse it wherever you want.
There are several other options like for example Cache, or a static property, or even read it from Configuration every time you want to use it. It really depends on the context of usage.
EDIT:
To read the connection string from configuration you can use the ConfigurationManager class from System.Configuration:
string conn = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString;
Keep the connection string name inside data-access layer and read it from Web.config every time you need (or cache it locally).