I am new to C# and need help with creating a class, which can be called in every newly created class and return connection to database. There is what I have done so far:
using System;
using MySql.Data.MySqlClient;
namespace SqlQueries
{
class DBConnect
{
public static void Main()
{
//Initialize();
}
private static MySqlConnection connection;
private static string server;
private static string database;
private static string uid;
private static string password;
public static void Initialize()
{
server = "testing.com";
database = "mus_le";
uid = "muff";
password = "test";
string connectionString = "Server=" + server + ";"+"Database=" + database + ";" + "Uid=" + uid + ";" + "Password=" + password + ";";
using (connection = new MySqlConnection(connectionString))
{
connection.Open();
}
}
}
public class Query
{
public void Select(string query)
{
DBConnect QConnect = new DBConnect();
// Here I want to call this class somewhere and pass
// query string to it and return result from select stmt
MySqlCommand command = new MySqlCommand(QConnect.Initialize(),query);
// here I get error Unable to convert void to string...
}
}
}
I am searching and reading from 2 days now, and there is nowhere solution to this problem, I am wondering what to do.Would be really really thankful if somebody of you guys give me books or something to read,and learn c# from.
First of, the MySqlCommand constructor takes a MySqlConnection and a string query as arguments but your DBConnect.Initialize method is void.
The second issue is that the connection is disposed as soon as it leaves the using statement in the Initialize method which means you can't reuse it (if that is what you trying to do..)
using (connection = new MySqlConnection(connectionString))
{
connection.Open();
}
What you can do instead is to return the connection from initialize and wrap your db operation in a using statement in the calling method
Update the DBConnect Initialize method to return the MySqlConnection instance
public static MySqlConnection Initialize()
{
server = "testing.com";
database = "mus_le";
uid = "muff";
password = "test";
string connectionString = "Server=" + server + ";"+"Database=" + database + ";" + "Uid=" + uid + ";" + "Password=" + password + ";";
return new MySqlConnection(connectionString);
}
Then use it
public void Select(string query)
{
using (var connection = DBConnect.Initialize())
using (var command = new MySqlCommand(connection,query))
{
}
}
Your method Initialize returns void, it should return the connection instead :
public static MySqlConnection Initialize()
{
server = "testing.com";
database = "mus_le";
uid = "muff";
password = "test";
string connectionString = "Server=" + server + ";"+"Database=" + database + ";" + "Uid=" + uid + ";" + "Password=" + password + ";";
return new MySqlConnection(connectionString))
}
and then you would use it like this :
public class Query
{
public void Select(string query)
{
DBConnect QConnect = new DBConnect();
// Here I want to call this class somewhere and pass
// query string to it and return result from select stmt
using (MySqlConnection conn = QConnect.Initialize())
{
conn.Open();
MySqlCommand command = new MySqlCommand(conn,query);
}
}
}
But as the comments say, these objects are usually provided...
If you want to reuse your class you can simply create is a base class for any others. Every newly created class can inherit from the base and have an access to database without reusing the code. There is a base method for Select(). You can add also any other SQL operation there.
public class DbContext
{
private static MySqlConnection connection;
private static string server;
private static string database;
private static string uid;
private static string password;
private static string ConnectionString = "Server=" + server + ";" + "Database=" + database + ";" + "Uid=" + uid + ";" + "Password=" + password + ";";
static DbContext()
{
server = "testing.com";
database = "mus_le";
uid = "muff";
password = "test";
}
protected object Select(string query)
{
using (connection = new MySqlConnection(connectionString))
{
connection.Open();
DBConnect QConnect = new DBConnect();
// Here I want to call this class somewhere and pass
// query string to it and return result from select stmt
MySqlCommand command = new MySqlCommand(QConnect.Initialize(), query);
// here I get error Unable to convert void to string...
//return result
return null;
}
}
}
public class SomeNewReader : DbContext
{
public object SelectSomething()
{
return base.Select("some query");
}
}
public class SomeNewReader1 : DbContext
{
public object SelectSomething()
{
return base.Select("some query");
}
}
To answer your question for books and something to read.
You should always look at learn.microsoft.com, often there are good examples that explain how these classes are used, additionally search for keywords on google or codeproject.com like listed below in combination with C# oder .NET
Data access layer (DAL)
Data access object (DAO)
Further, you can improve your skills with reading something about OOP design patterns Elements of Reusable Object-Oriented Software - Erich Gamma et al.
e.g. Factory Pattern - should be used to create a specific database from an abstraction
In the modern OOP frameworks today, you will find implementations with using dependency injection to decouple infrastructure code (e.g. your database and sql-statements) from business logic (e.g. specific operations on data).
For the csharp-language itself they are literally available as the sand of the sea. It depends on your OOP and programming skills which one fits for you. Professional C# 7 and .NET Core
Related
Through the information I have found searching here on stackoverflow, I have what I think is 90% of this solved but because of how OleDbConnection is converted to define SqlConnection, the call to the class with the connection and test script wants definition I am unsure how to provide.
I've used these pages to get what I have so far
How to create an SqlConnection in C# to point to UDL file
Calling an SQL Connection method in C#
private static string CONNECTION_NAME = #"C:\Temp\DisplayDB.udl";
public static class MyConnection
{
public static SqlConnection GetSqlConnection()
{
var udlInfo = new OleDbConnection($"File Name={CONNECTION_NAME}");
return CreateSqlConnection(udlInfo);
}
public static SqlConnection CreateSqlConnection(OleDbConnection udlInfo)
{
try
{
string CONNECTION_STRING = $"Database={udlInfo.Database};Server={udlInfo.DataSource};User ID=User;Password=13245;Integrated Security=True;connect timeout = 30";
var connection = new SqlConnection(CONNECTION_STRING);
connection.Open();
return connection;
}
catch
{
Console.WriteLine($"{CONNECTION_NAME} Not found");
return null;
}
}
}
private void DBCheck()
{
// The line below is my issue, mouseover error of ".CreateSqlConnection"
// says there is no argument given that corresponds to the required
// formal parameter 'udlInfo' of
// 'MainWindow.MyConnection.CreateSqlConnection(OleDbConnection)'
using (var con = MyConnection.CreateSqlConnection())
{
con.Open();
var command = new SqlCommand("IF DB_ID ('CodeTest') IS NULL " +
"BEGIN " +
"USE MASTER " +
"CREATE DATABASE CodeTest" +
" END", con);
var reader = command.ExecuteReader();
reader.Close();
con.Close();
}
}
I expect the WPF to use the Database and Server from the UDL file to make the SqlConnection so I can run queries and commands. I understand the security part of UDL in plain text but I do not want hard coded values as this application will be used in various environments nor do I want those values to need definition on each launch of the app.
My MySQL connection throws null reference although this code worked well one year ago.
The line where the debugger indicates the exception contains
"connection = new MySqlConnection(connectionString);":
DBConnect MySqlConnection = new DBConnect();
string[] resultArray = MySqlConnection.GetValidUser(
"tbl_user",
tbEmail.Text,
tbPassword.Text
);
//THROWS null reference exception in method 'private bool OpenConnection()'
//A first chance exception of type 'System.ArgumentException' occurred in System.Data.dll
This is my DBConnect class:
class DBConnect
{
private MySqlConnection connection;
private string server;
private string database;
private string uid;
private string password;
public DBConnect()
{
server = "x.x.x.x";
database = "...";
uid = "...";
password = "...";
string connectionString = "SERVER=" + server + ";" +
"DATABASE=" + database + ";" +
"UID=" + uid + ";" +
"PASSWORD=" + password + ";";
connection = new MySqlConnection(connectionString);
}
private bool OpenConnection()
{
try
{
connection.Open();
return true;
}
catch (MySqlException ex)
{
switch (ex.Number)
{
case 0:
MessageBox.Show("Cannot connect to MySQL server.");
break;
case 1045:
MessageBox.Show("Invalid username or password.");
break;
}
return false;
}
}
public string[] GetValidUser(string dbTable, string dbUsername, string dbPassword)
{
string query = "SELECT id,email,password FROM " + dbTable +
" WHERE email='" + dbUsername +
"' AND password='" + dbPassword + "'";
string[] resultArray = new string[3];
if (this.OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, connection);
MySqlDataReader dataReader = cmd.ExecuteReader();
while (dataReader.Read())
{
resultArray[0] = dataReader.GetInt32(0).ToString();
resultArray[1] = dataReader.GetString(1);
resultArray[2] = dataReader.GetString(2);
}
dataReader.Close();
this.CloseConnection();
}
return resultArray;
}
}
The original code for the database class can be found here.
This is not an answer to the NullReferenceException - we're still working through that in the comments; this is feedback for the security parts.
The first thing we can look at is SQL injection; this is very easy to fix - see below (note I've tidied some other things too)
// note: return could be "bool" or some kind of strongly-typed User object
// but I'm not going to change that here
public string[] GetValidUser(string dbUsername, string dbPassword)
{
// no need for the table to be a parameter; the other two should
// be treated as SQL parameters
string query = #"
SELECT id,email,password FROM tbl_user
WHERE email=#email AND password=#password";
string[] resultArray = new string[3];
// note: it isn't clear what you expect to happen if the connection
// doesn't open...
if (this.OpenConnection())
{
try // try+finally ensures that we always close what we open
{
using(MySqlCommand cmd = new MySqlCommand(query, connection))
{
cmd.Parameters.AddWithValue("email", dbUserName);
// I'll talk about this one later...
cmd.Parameters.AddWithValue("password", dbPassword);
using(MySqlDataReader dataReader = cmd.ExecuteReader())
{
if (dataReader.Read()) // no need for "while"
// since only 1 row expected
{
// it would be nice to replace this with some kind of User
// object with named properties to return, but...
resultArray[0] = dataReader.GetInt32(0).ToString();
resultArray[1] = dataReader.GetString(1);
resultArray[2] = dataReader.GetString(2);
if(dataReader.Read())
{ // that smells of trouble!
throw new InvalidOperationException(
"Unexpected duplicate user record!");
}
}
}
}
}
finally
{
this.CloseConnection();
}
}
return resultArray;
}
Now, you might be thinking "that's too much code" - sure; and tools exist to help with that! For example, suppose we did:
public class User {
public int Id {get;set;}
public string Email {get;set;}
public string Password {get;set;} // I'll talk about this later
}
We can then use dapper and LINQ to do all the heavy lifting for us:
public User GetValidUser(string email, string password) {
return connection.Query<User>(#"
SELECT id,email,password FROM tbl_user
WHERE email=#email AND password=#password",
new {email, password} // the parameters - names are implicit
).SingleOrDefault();
}
This does everything you have (including safely opening and closing the connection), but it does it cleanly and safely. If it method returns a null value for the User, it means no match was found. If a non-null User instance is returned - it should contain all the expected values just using name-based conventions (meaning: the property names and column names match).
You might notice that the only code that remains is actually useful code - it isn't boring plumbing. Tools like dapper are your friend; use them.
Finally; passwords. You should never store passwords. Ever. Not even once. Not even encrypted. Never. You should only store hashes of passwords. This means that you can never retrieve them. Instead, you should hash what the user supplies and compare it to the pre-existing hashed value; if the hashes match: that's a pass. This is a complicated area and will require significant changes, but you should do this. This is important. What you have at the moment is insecure.
Among other things, it sounds like you have problems with the connection string - from comments:
While "connection = new MySqlConnection(); connection.ConnectionString = connectionString;" throws an exception the statement "connection = new MySqlConnection();" does not...
The difference here is simply: in the latter you aren't setting the connection string - so it sounds like your connection string is not correctly escaping the values (most likely, the password); you could try:
var cs = new DbConnectionStringBuilder();
cs["SERVER"] = server;
cs["DATABASE"] = database;
cs["UID"] = uid;
cs["PASSWORD"] = password;
var connectionString = cs.ConnectionString;
I am new to .Net and C# and I have been struggling to get my head round on how to utilise a sql connection created in one section of the code and use it in another. I got 2 buttons on my form. One connects to the database and the other inserts to a table. How do I use the connection variable when inserting to the table?
I hope this makes sense. Thanks
namespace SQL
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnConnect_Click(object sender, EventArgs e)
{
SqlOperations connect = new SqlOperations();
connect.connectToSQL("server=localhost\\SQLExpress;", "database=Cromwell; ");
}
private void btnAddToDatabase_Click(object sender, EventArgs e)
{
SqlOperations addToTable = new SqlOperations();
addToTable.InsertToTable("InputDir", "C:\\");
}
}
public class SqlOperations
{
public bool connectToSQL(string sqlHost, string database)
{
SqlConnection SqlConnect = new SqlConnection("user id=userid;" +
"password=validpassword;" + sqlHost +
"Trusted_Connection=yes;" +
database + "connection timeout=30");
try
{
SqlConnect.Open();
MessageBox.Show("Connected to SQL Express");
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return false;
}
}
public bool InsertToTable(string columnName, string value)
{
SqlCommand myCommand = new SqlCommand();
myCommand.Connection = **SqlConnect**; // THIS BIT COMPLAINS
myCommand.CommandText = "INSERT INTO Config (" + columnName + ") " +
"Values ('" + value + "')";
}
}
}
Solution 1: You can create your connection string as constant string variable and access it using class name from whereever you need it as constant variables are implicitly static(you can access them as global variables)
Try This:
Class MyConnectionString
{
const string strCon="user id=userid;password=validpassword;
server=localhost\\SQLExpress;database=Cromwell;
Trusted_Connection=yes;connection timeout=30";
}
while accessing :
SqlConnection scon=new SqlConnection(MyConnectionString.strCon);
Solution 2:
Create your connection string in Configuration file and access it.
<connectionStrings>
<add name="myConString"
connectionString="user id=userid;password=validpassword;
server=localhost\\SQLExpress;database=Cromwell;
Trusted_Connection=yes;connection timeout=30" />
</connectionStrings>
use it whenever you need it:
string ConnectionString =
ConnfigurationManager.ConnectionStrings["myConString"].ConnectionString;
Check this link, http://www.codeproject.com/Articles/4416/Beginners-guide-to-accessing-SQL-Server-through-C . It is a beginners guide to access SQL Databases using c#.NET.
You can also add the connection string in your web.config, or app.config and then access it from c# code.
C#
// Add a reference at the top of your code file
using System.Configuration;
// Within the code body set your variable
string cs = ConfigurationManager.ConnectionStrings["connectionStringName"].ConnectionString;
VB
' Add a reference at the top of your code file
Imports System.Configuration
' Within the code body set your variable
Dim cs as String = ConfigurationManager.ConnectionStrings("connectionStringName").ConnectionString
Obviously remember to add this (With your own connection string) in your web.config
<connectionStrings>
<add name="ConnStringDb1" connectionString="Data Source=localhost;Initial Catalog=YourDataBaseName;Integrated Security=True;" providerName="System.Data.SqlClient" />
I like that you've defined a class to connect to SQL. You can use that class to manage the lifecycle of your SQL connections, which is a good thing. It would also be good if it handled the connection credentials too so your callers don't have to know what it is. How about this:
public class SqlOperations
{
private SqlConnection Connect()
{
... Get SQL credentials here
... Open and return connection here
}
public bool InsertToTable(string columnName, string value)
{
using (var conn = Connect())
{
using (SqlCommand myCommand = new SqlCommand())
{
myCommand.Connection = conn;
... do your myCommand stuff here
}
}
}
}
Then in your form ditch the connect-to-db button - it's managed for you! All you need is your insert button with this event:
private void btnAddToDatabase_Click(object sender, EventArgs e)
{
SqlOperations addToTable = new SqlOperations();
addToTable.InsertToTable("InputDir", "C:\\");
}
The error with ExecuteReader: Connection property has not been initialized is giving me a fit. I think I have it set up right. I will show you how I create the mssql connection and then what I am requesting, and the class I created to read/write and open/close the connection. (Three different parts of the app but I just lumped them together so you could see the actual logic flow I hope.)
What am I missing, or where am I supposed to put the connection? Example? I appreciate the help!
Here is the using statement I start with:
using (MSSQL mssqldb = new MSSQL(Constants.msSqlServer, Constants.msSqlDb, Constants.msSqlUid, Constants.msSqlPswd))
Here is where I say "Hey, get me my data using my MSSQL class"
using (var results = mssqldb.Read("SELECT TOP 1 * FROM AlertLog ORDER BY AlarmID DESC"))
{
results.Read();
legacyAlert = Int32.Parse(results["AlarmId"].ToString().Trim());
}
Here is the MSSQL class
class MSSQL : IDisposable
{
public MSSQL(string server, string database, string uid, string pswd)
{
string msSqlConnectionString = #"Data Source=" + server + ";Initial Catalog=" + database + ";user id=" + uid + ";password=" + pswd;
SqlConnection msqlConnection = new SqlConnection(msSqlConnectionString);
msqlConnection.Open();
Console.WriteLine("MS SQL OPEN!");
}
public void Write(string sql)
{
using (SqlCommand myCommand = new SqlCommand(sql, msqlConnection))
myCommand.ExecuteNonQuery();
}
public SqlDataReader Read(string sql)
{
using (SqlCommand myCommand = new SqlCommand(sql, msqlConnection))
return myCommand.ExecuteReader();
}
public void Dispose()
{
try {
msqlConnection.Close();
}
catch (SqlException ex) {
Console.Error.WriteLine("MS SQL Error - Closing Database");
Console.Error.WriteLine(ex);
}
msqlConnection.Dispose();
}
private SqlConnection msqlConnection;
}
msqlConnection is null.
Your constructor creates a local variable named msqlConnection, but does not assign to the field.
Before anyone votes my question down, I would like to say that this is my first time using classes in C# and I have done a lot of research but I am still encountering errors. Newbie here.
I am trying to put the Insert, Delete, Update, and Count statements in a class file so that my code will be neat.
Here is the class file I made (with the help of research of course):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;
using System.IO;
using System.Windows.Forms;
namespace classlib
{
public class DBConnect
{
private static MySqlConnection mycon;
private string server;
private string database;
private string uid;
private string password;
public DBConnect()
{
Initialize();
}
private void Initialize()
{
server = "localhost";
database = "restaurantdb";
uid = "user";
password = "root";
string connectionString;
connectionString = "SERVER=" + server + ";" + "DATABASE=" + database + ";" + "UID=" + uid + ";" + "PASSWORD=" + password + ";";
mycon = new MySqlConnection(connectionString);
}
private static bool OpenConnection()
{
try
{
mycon.Open();
return true;
}
catch (MySqlException ex)
{
switch (ex.Number)
{
case 0:
MessageBox.Show("Cannot connect to server. Contact administrator");
break;
case 1045:
MessageBox.Show("Invalid username/password, please try again");
break;
}
return false;
}
}
private static bool CloseConnnection()
{
try
{
mycon.Close();
return true;
}
catch (MySqlException ex)
{
MessageBox.Show(ex.Message);
return false;
}
}
public static void Insert(string query)
{
if (OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, mycon);
cmd.ExecuteNonQuery();
CloseConnnection();
}
}
public static void Update(string query)
{
if (OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand();
cmd.CommandText = query;
cmd.Connection = mycon;
cmd.ExecuteNonQuery();
CloseConnnection();
}
}
public static void Delete(string query)
{
if (OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, mycon);
cmd.ExecuteNonQuery();
CloseConnnection();
}
}
public static int Count(string query)
{
int count = -1;
if (OpenConnection() == true)
{
MySqlCommand cmd = new MySqlCommand(query, mycon);
count = int.Parse(cmd.ExecuteScalar() + "");
CloseConnnection();
return count;
}
else
{
return count;
}
}
}
}
I was just trying the Count Method like in a certain form. Here is my code:
MessageBox.Show("NUMBER OF ACCOUNTS IN DATABASE = "+ DBConnect.Count("SELECT count(*) FROM usersettingsdb") +"", "CONFIRMATION");
But I get this error on the class file on the OpenConnection() method on the mycon.Open() line:
Object reference not set to an instance of an object.
How do I remove the said error and access the methods through calling it like so DBConnect.MethodName()?
I don't quite get anything about classes but I would really like to know how I can create my own functions/methods so as to keep my code neat.
Ok this is because you are messing up thing using in some cases static fields and in other cases not. There are tons of paper about static classes/members, see here for example.
The initialization code won't be called if you use the class as you are using.
In your case you should have a DBConnect instance and remove the static from methods
var db = new DBConnect();
and then use that in order to make queries:
db.Count(...);
Another solution is to call the Initialize method inside the Count method. You should modify Initialize in order to make it static (you will have to make all of your fields as static)
Another users will answer this question propably. So I want to mention different things. Your code is not very good. Instead of using it ,you can take a look at use of repository pattern. You can also use petapoco for database. These facilitate your work.
http://www.remondo.net/repository-pattern-example-csharp/
http://www.toptensoftware.com/petapoco/
Your myCon object is initialized in the Initialize() method, which is called in the constructor of the class, so only when you create an instance of DbConnect.
mycon = new MySqlConnection(connectionString);
In your code, you have no instance of DbConnect, you just call the static method Count of the class. So, the myCon is null.