Calling a MySQL Routine in C# - c#

Please accept my apologies if I'm getting my verbiage wrong; I'm just now learning C# (my background is mostly Visual Basic and PHP).
What I'm trying to do is create a class / routine in C# (Windows Forms) for connecting and disconnecting to a MySQL database that can then be reused throughout the rest of my project without having to reiterate the code every time.
I've got my class / routine setup, but I'm stuck on trying to call it from the rest of my project. I know in Visual Basic this was a fairly simple task to do, but I just can't seem to figure it out how to do it in C#.
Any suggestions? Thank you in advance.
public void dbDisconnect(object sender, EventArgs e)
{
try
{
MySqlConnection connection = new MySqlConnection(Properties.Settings.Default.mysql_db_conn_string);
connection.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

Here's a method I currently have in my app:
public static MySqlConnection CreateConnection(
string mysqlServer,
string mysqlUser,
string mysqlPassword,
string mysqlDatabase)
{
MySqlConnection mysqlConnection = null;
string mysqlConnectionString = String.Format(
"server={0};uid={1};pwd={2};database={3};DefaultCommandTimeout={4};",
mysqlServer, mysqlUser, mysqlPassword, mysqlDatabase, 120);
/**
** Workaround for MySQL 5.6 bug:
** http://stackoverflow.com/questions/30197699/reading-from-stream-failed-mysql-native-password-error
*/
int tryCounter = 0;
bool isConnected = false;
do
{
tryCounter++;
try
{
mysqlConnection = new MySqlConnection();
mysqlConnection.ConnectionString = mysqlConnectionString;
mysqlConnection.Open();
if (mysqlConnection.State == ConnectionState.Open)
{
isConnected = true;
}
}
catch (MySqlException ex)
{
if (tryCounter < 10)
{
DebugLog.Dump(ex.ToString(), DebugLog.MainLogFilePath);
Thread.Sleep(10000); // 10 seconds.
}
else
{
throw;
}
}
} while (!isConnected);
return mysqlConnection;
}
Usage:
using (MySqlConnection hostsDbConnection = HostsDbConnector.CreateConnection())
{
// Do something...
}
With using keyword you don't need to close the connection manually, it'll be closed automatically when it's no longer needed.

Related

C# WinUI 3 Desktop Application Issue with ContentDialog and the XamlRoot

I am building a C# WinUI 3 desktop app running on Windows 10. I want to use a contentdialog to display error messages.
I am calling this method from multiple catch clauses:
private async void DisplayErrorDialog(string content)
{
ContentDialog ErrorDialog = new ContentDialog()
{
Title = "* Error *",
Content = content,
CloseButtonText = "Ok"
};
// XamlRoot must be set in the case of a ContentDialog running in a Desktop app
ErrorDialog.XamlRoot = this.Content.XamlRoot;
ContentDialogResult result = await ErrorDialog.ShowAsync();
}
Here is how I call the method:
catch (SqlException Sql_Error)
{
Debug.WriteLine($"Hello SQL error GetSQLData_App_View_Results_2020: {Sql_Error.Message}");
DisplayErrorDialog($"GetSQLData_App_View_Results_2020 (SQL Error): {Sql_Error.Message}");
}
catch (Exception Other_Error)
{
Debug.WriteLine($"Hello Other error GetSQLData_App_View_Results_2020: {Other_Error.Message}");
DisplayErrorDialog($"GetSQLData_App_View_Results_2020 (Other Error): {Other_Error.Message}");
}
}
I have many other contentdialogs working successfully within my application. I wanted/needed to test this error contentdialog so I explicitly threw an exception this way:
throw new Exception("SQL test exception #1");
The throw does work and the catch clause 'catches' the exception. However I am getting this error in the contentdialog:
Exception thrown at 0x00007FFFD5FE3FA9 (KernelBase.dll) in MetricReporting.exe: WinRT originate error - 0x80070057 : 'This element is already associated with a XamlRoot, it cannot be associated with a different one until it is removed from the previous XamlRoot.'.
I cannot figure this out. I am a beginner C# and WinUI 3 developer. Thank you for your help and guidance.
Thank you Andrew for your observation.
Here is more of my code:
public pageResults()
{
this.InitializeComponent();
Debug.WriteLine($"### --- InitializeComponents() Completed --- ###");
FetchSQLData_Ref_Metric();
FetchSQLData_Ref_Metric_MarketID();
FetchSQLData_StateCodes();
FetchSQLData_MetricYear();
FetchSQLData_Results();
Display_Results();
}
I am doing a lot of sql fetching of data into datatables and then I display the datatable in a datagrid on the page, which is part of a navigationview.
I inserted the 'throw' inside of a method that is inside of 'FetchSQLData_Results()'
private void FetchSQLData_Results()
{
string metricYear = string.Empty;
// Pre-load all views into their own separate datatables. Each views represents a metric year.
// At this time there are views for 2020, 2021, and 2022
foreach (DataRow row in dtMetricYear.Rows)
{
metricYear = row["metricyear"].ToString();
GetSQLData_App_View_Results_(metricYear);
}
}
private void GetSQLData_App_View_Results_(string metricYear)
{
// Load datatables with existing views
switch (metricYear)
{
case "2020":
GetSQLData_App_View_Results_2020();
break;
case "2021":
GetSQLData_App_View_Results_2021();
break;
case "2022":
GetSQLData_App_View_Results_2022();
break;
case "2023":
break;
case "2024":
break;
default:
break;
}
}
The throw is here:
public void GetSQLData_App_View_Results_2020()
{
try
{
using (SqlConnection con = new SqlConnection("Data Source = xxxx; Initial Catalog = xxxx; Integrated Security = True; Connect Timeout = 15; Encrypt = False; TrustServerCertificate = True; ApplicationIntent = ReadWrite; MultiSubnetFailover = False"))
{
**//throw new Exception("SQL test exception #1");**
//Prepare sql
//string sql = "select * from dbo.app_emb_prd_lvl_results_2020 order by metric_id";
string sql = "select * from app_emb_prd_lvl_results_2020 v join dbo.Ref_Metric r on v.metric_id = r.Metric_ID order by v.metric_id";
SqlCommand cmd = new SqlCommand(sql, con);
cmd.CommandType = System.Data.CommandType.Text;
//Open the connection
con.Open();
// Create adapter and fill the datatable with returned data from sql command
using (SqlDataAdapter adap = new SqlDataAdapter(cmd))
{
dtResults2020.Clear();
adap.Fill(dtResults2020);
try
{.. intentionally left blank ..}
catch (Exception List_Error)
{
Debug.WriteLine($"List error GetSQLData_App_View_Results_2020: {List_Error.Message}");
}
Debug.WriteLine($"GetSQLData_App_View_Results_2020 Completed");
} // end using sql adapter
} // end using sql connection
}
catch (SqlException Sql_Error)
{
Debug.WriteLine($"Hello SQL error GetSQLData_App_View_Results_2020: {Sql_Error.Message}");
DisplayErrorDialog($"GetSQLData_App_View_Results_2020 (SQL Error): {Sql_Error.Message}");
}
catch (Exception Other_Error)
{
Debug.WriteLine($"Hello Other error GetSQLData_App_View_Results_2020: {Other_Error.Message}");
DisplayErrorDialog($"GetSQLData_App_View_Results_2020 (Other Error): {Other_Error.Message}");
}
}
As I mentioned in the comments, XamlRoad might not be ready. Try fetching your data in Loaded instead of the constructor.
public pageResults()
{
this.InitializeComponent();
this.Loaded += pageResults_Loaded;
Debug.WriteLine($"### --- InitializeComponents() Completed --- ###");
}
private void pageResults_Loaded(object sender, RoutedEventArgs e)
{
FetchSQLData_Ref_Metric();
FetchSQLData_Ref_Metric_MarketID();
FetchSQLData_StateCodes();
FetchSQLData_MetricYear();
FetchSQLData_Results();
Display_Results();
}

Reading access database, background process still running on close

So I am using c# windows form with visual studio to query an access database.
When I run with debugger and stop the application from within visual studio there is no problem, however when I run WITHOUT debugger, query the database and then close using X, the process which appears under "Apps" in Task manager becomes a background process. I can have multiple instances of this process if I run the application numerous times.
I would appreciate any information on this, Thanks!
Here is the code I am using.
private void BtnSendQuery_Click(object sender, EventArgs e)
{
ReadDatabase();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
var x = MessageBox.Show("Are you sure you want to exit? ", "Exit", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
if (x == DialogResult.No)
{
e.Cancel = true;
}
else
{
e.Cancel = false;
}
}
private void ReadDatabase()
{
string CONNECTION_STR = #"Provider=Microsoft.ACE.OLEDB.12.0;
Data Source = C:\\Users\\***\\Documents\\db_folder\\access_db.accdb;
Persist Security Info = False";
string query = ""; // query string
OleDbConnection DB_CONNECTION = null;
try
{
DB_CONNECTION = new OleDbConnection(CONNECTION_STR);
DB_CONNECTION.Open();
query = TbInputQuery.Text;
var command = new OleDbCommand(query, DB_CONNECTION);
var str = new StringBuilder();
using (OleDbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
str.AppendLine(reader["ID"].ToString());
}
TbOutputTable.Text = str.ToString();
}
DB_CONNECTION.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
if (DB_CONNECTION != null)
{
DB_CONNECTION.Close();
}
}
}
}
As general rule, both your connection and cmdSQL or reader should be in a using block.
While your reader is in a using block, the ALL important connection object is not.
In fact, once beyond the using block for connection? You could get away not even having using blocks for the command and reader object.
And even if a trapped error, or UN-trapped error occurs? The using block WILL ALWAYS clean up the connection.
So, for command and reader - not end of world for using block.
But, for connection? yes, always do that.
Project->settings - I would use the connection builder for the connection string - not put in code.
eg this one:
Then use advanced, and make sure you choose ACE (for accdb) or JET (for mdb)
So this:
So, with above setting, then we have ONE spot in the system - never typing connecting string by hand or having to place in the code (makes change of connection very hard).
Also, don't use "any cpu" force the project to x86 for using Access x32
(or if using x64, then force project to that).
So, code say like this:
private void ReadDatabase()
{
string CONNECTION_STR = Properties.Settings.Default.AccessDB;
string query = ""; // query string
try
{
using (OleDbConnection DB_CONNECTION = new OleDbConnection(CONNECTION_STR))
{
using (OleDbCommand command = new OleDbCommand(query, DB_CONNECTION))
{
DB_CONNECTION.Open();
var str = new StringBuilder();
using (OleDbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
str.AppendLine(reader["ID"].ToString());
}
TbOutputTable.Text = str.ToString();
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
}
}
Note in above - don't really care about the catch block - as long as the using block for the connection is built - it gets cleaned up no matter what - and even if no try/catch, or if in fact you have one!!
And if a error trigger - still again, note how we do NOT have to clean up, or close the connection.

How to check if remote database MYSQL is available

I need register the user access on my webpage aspx in MySQL remote Database.
But this MySQL remote Database it could be unavailable.
I have tried this code, but how to execute the RegisterUSer() method in the bool IsServerConnected() method ?
public bool IsServerConnected()
{
using (var l_oConnection =
new OdbcConnection(ConfigurationManager.ConnectionStrings["ConnMySQL"].ConnectionString))
{
try
{
l_oConnection.Open();
return true;
}
catch (OdbcException)
{
return false;
}
}
}
private void RegisterUSer()
{
using (OdbcConnection myConnectionString =
new OdbcConnection(ConfigurationManager.ConnectionStrings["ConnMySQL"].ConnectionString))
{
string sql = #String.Format(" INSERT IGNORE INTO tbl_user ");
sql += String.Format(" ... ");
using (OdbcCommand command =
new OdbcCommand(sql, myConnectionString))
{
try
{
command.Connection.Open();
command.ExecuteNonQuery();
}
catch (Exception ex)
{
throw ex;
}
finally
{
command.Connection.Close();
}
}
#Edit 01
Error :
The type or namespace name 'resultType' could not be found (are you
missing a using directive or an assembly reference?)
You could just do a "wrapper" method that calls first to IsServerConnected() and depending on the returned boolean then calls RegisterUSer() or throws an error if the database is not availiable.
Quick and dirty pseudocode
private resultType ChickenWrapMethod()
{
if (!IsServerConnected())
{
//Throw some error here and exit
}
RegisterUSer()
}
BTW...in my opinion you should consider opening the sql connection out of the methods so it can be shared by both operations
Try this in c#. I hope I was helpful.
using System.Net.NetworkInformation;
var ping = new Ping();
var reply = ping.Send("XX.XX.XX.XXX", 60 * 1000); // 1 minute time out (in ms)
if (reply.Status == IPStatus.Success)
{
Response.Write("Server XX.XX.XX.XXX is up");
RegisterUSer();
}
else
{
Response.Write("Server XX.XX.XX.XXX is down");
}

Delay to SQL Server throw an exception

I have this Code to Get a table Data From SQL Server:
public static System.Data.Linq.Table<Equipment> GetEquipmentTable()
{
DataClassesDataContext dc = new DataClassesDataContext();
return dc.GetTable<Equipment>();
}
I Have a Button to call this Function :
private void button_Click(object sender, RoutedEventArgs e)
{
MyListView.DataContext = GetEquipmentTable();
}
My Problem is :When I Disable Communication Between my App and SQL Server Machine and then click this button, It takes a while to throw an Exception that Connect to Database is impossible!!!! My major problem is that my app freezed till this Exception accrued.
Did I missed something ?
Update 1 :
I used async and wait base on Rahul solution
public static async Task<System.Data.Linq.Table<Equipment>> GetEquipmentTable()
{
DataClassesDataContext dc = new DataClassesDataContext();
return dc.GetTable<Equipment>();
}
private async void button_Click(object sender, RoutedEventArgs e)
{
MyListView.DataContext = await GetEquipmentTable();
}
but it still wait for this line of code :
return dc.GetTable<Equipment>();
and UI freezes as well.
I think dc.gettable<> is not waitable or somthing else !!??
When I Disable Communication Between my App and SQL Server Machine and
then click this button
That's obvious right since it tries to connect to the machine (within the Timeout mentioned in connection string) and then throws the exception back once it finds that the server isn't reachable.
major problem is that my app freezed till this Exception accrued
Probably in that case make the method as async method like
public static async Task<System.Data.Linq.Table<Equipment>> GetEquipmentTable()
{
DataClassesDataContext dc = new DataClassesDataContext();
return dc.GetTable<Equipment>();
}
Your event handler
private async void button_Click(object sender, RoutedEventArgs e)
{
MyListView.DataContext = await GetEquipmentTable();
}
You have two problems, the app freezing is because you are not using asynchronous programming.
The delay before the connection exception is because the client side app waits until the connection timeout timer finishes (30 seconds default).
Try using async await on your database calls to free up the UI.
Try changing the connection timeout to 5 seconds in the connection string.
Change in connection string:
"Data Source=...;Connect Timeout=5"
Use await as in the answer from Rahul. +1
You could also test a simple SqlConnection.Open
private static bool OpenSqlConnection(string connectionString)
{
bool return = false;
try
{
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
return = true;
}
catch (Exception ex)
{
return = false;
}
finally
{
connection.Close();
}
return return;
}
Could use SqlConnection.OpenAsync.
SqlConnection con = new SqlConnection("connection string");
bool resp = false;
try
{
con.OpenAsync();
resp = true;
}
catch (SqlException ex)
{
//use the ex message
resp = false;
}
catch (Exception ex)
{
resp = false;
}
finally
{
con.Close();
}

MySql executing a MySqlScript even when the connection has been closed

Is it possible for mysql to execute a script even when the connection has been closed?
I am using mysql community server , through a .NET connector API.
Was using c# to test out the API.
I have the following static class
using System;
using System.Data;
using MySql.Data;
using MySql.Data.MySqlClient;
public static class DataBase
{
static string connStr = "server=localhost;user=root;port=3306;password=*******;";
static MySqlConnection conn;
public static bool Connect()
{
conn = new MySqlConnection(connStr);
try
{
conn.Open();
}
catch (Exception Ex)
{
ErrorHandler(Ex);
return false;
}
return true;
}
public static int ExecuteScript(string scripttext) // returns the number of statements executed
{
MySqlCommand cmd = conn.CreateCommand();
cmd.CommandText = scripttext;
MySqlScript script;
int count= 0;
try
{
script = new MySqlScript(conn, cmd.CommandText);
script.Error += new MySqlScriptErrorEventHandler(script_Error);
script.ScriptCompleted += new EventHandler(script_ScriptCompleted);
script.StatementExecuted += new MySqlStatementExecutedEventHandler(script_StatementExecuted);
count = script.Execute();
}
catch (Exception Ex)
{
count = -1;
ErrorHandler(Ex);
}
return count;
}
# region EventHandlers
static void script_StatementExecuted(object sender, MySqlScriptEventArgs args)
{
string Message = "script_StatementExecuted";
}
static void script_ScriptCompleted(object sender, EventArgs e)
{
string Message = "script_ScriptCompleted!";
}
static void script_Error(Object sender, MySqlScriptErrorEventArgs args)
{
string Message = "script_Error: " + args.Exception.ToString();
}
# endregion
public static bool Disconnect()
{
try
{
conn.Close();
}
catch (Exception Ex)
{
ErrorHandler(Ex);
return false;
}
return true;
}
public static void ErrorHandler(Exception Ex)
{
Console.WriteLine(Ex.Source);
Console.WriteLine(Ex.Message);
Console.WriteLine(Ex.ToString());
}
}
and I am using the following code to test out this class
using System;
using System.Data;
namespace Sample
{
public class Sample
{
public static void Main()
{
if (DataBase.Connect() == true)
Console.WriteLine("Connected");
if (DataBase.Disconnect() == true)
Console.WriteLine("Disconnected");
int count = DataBase.ExecuteScript("drop database sample");
if (count != -1)
{
Console.WriteLine(" Sample Script Executed");
Console.WriteLine(count);
}
Console.ReadKey();
}
}
}
I noticed that even though I have closed my MySql connection using Disconnect() - which i have defined, mysql continues to execute the command i give next and no error is generated.
I feel like I am doing something wrong, as an error should be generated when i try to execute a script on a closed connection.
Is it a problem in my code/logic or some flaw in mysql connector?
I did check through the mysql workbench whether the command was executed properly and it was.
This is a decompile of MySqlScript.Execute code....
public unsafe int Execute()
{
......
flag = 0;
if (this.connection != null)
{
goto Label_0015;
}
throw new InvalidOperationException(Resources.ConnectionNotSet);
Label_0015:
if (this.query == null)
{
goto Label_002A;
}
if (this.query.Length != null)
{
goto Label_002C;
}
Label_002A:
return 0;
Label_002C:
if (this.connection.State == 1)
{
goto Label_0047;
}
flag = 1;
this.connection.Open();
....
As you can see, when you build the MySqlScript the connection passed is saved in an internal variable and before executing the script, if the internal connection variable is closed, the code opens it. Not checked but I suppose that it also closes the connection before exiting (notice that flag=1 before opening)
A part from this I suggest to change your code to avoid keeping a global MySqlConnection object. You gain nothing and risk to incur in very difficult bugs to track.
static string connStr = "server=localhost;user=root;port=3306;password=*******;";
public static MySqlConnection Connect()
{
MySqlConnection conn = new MySqlConnection(connStr);
conn.Open();
return conn;
}
This approach allows to write code that use the Using Statement
public static int ExecuteScript(string scripttext) // returns the number of statements executed
{
using(MySqlConnection conn = Database.Connect())
using(MySqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = scripttext;
....
}
}
The Using statement will close and dispose the connection and the command freeing valuable resources and also in case of exception you will be sure to have the connection closed and disposed

Categories