Mysql Windows Forms | Connection must be valid and open - c#

Good day, friends, help to finalize this class, here's the thing:
I'm trying to make it so that if there is no connection to the database, one action will be performed in the form, there will be a connection to the database, we perform another action.
Now the problem is that if you do not connect to the database, there will be terrible lags of the application itself.
using System;
using MySql.Data.MySqlClient;
namespace Launcher.SupportClass
{
public class Web_MysqlDataBase : IDisposable
{
MySqlConnection connection = new MySqlConnection("server=127.0.0.1;port=3306;username=root;password=1234;database=test-test;");
public bool Connection_BD;
public void OpenConnect()
{
if (connection.State == System.Data.ConnectionState.Closed)
{
try
{
connection.Open();
CheckConnect();
}
catch
{
CheckConnect();
}
finally
{
CheckConnect();
closedConnection();
}
}
}
public void closedConnection()
{
if (connection.State == System.Data.ConnectionState.Open)
{
connection.Close();
}
}
public MySqlConnection getConnection()
{
return connection;
}
public void Dispose()
{
Dispose(true);
}
public void CheckConnect()
{
if (connection.State == System.Data.ConnectionState.Open)
{
Connection_BD = true;
}
if (connection.State == System.Data.ConnectionState.Closed)
{
Connection_BD = false;
}
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// free managed resources
if (connection.State != System.Data.ConnectionState.Open)
{
connection.Close();
connection = null;
Dispose();
}
}
}
}
}
Next, I want to perform this simple construction, but there are already errors, what am I doing wrong?
Web_MysqlDataBase bd = new Web_MysqlDataBase();
bd.OpenConnect();
string query = "SELECT `text_update` FROM `launcher` WHERE `opened`='1'";
MySqlCommand command = new MySqlCommand(query, bd.getConnection());
if (bd.Connection_BD == true)
{
DataTable table = new DataTable();
MySqlDataAdapter adapter = new MySqlDataAdapter();
adapter.SelectCommand = command;
adapter.Fill(table);
if (table.Rows.Count > 0)
{
string name = command.ExecuteScalar().ToString();
ScrollingLeable.Text = name;
ScrollingLeable.position = 750;
ScrollsLeable.Visible = true;
ScrollingLeable.Visible = true;
}
else
{
ScrollsLeable.Visible = false;
ScrollingLeable.Visible = false;
}
}
else
{
ScrollsLeable.Visible = false;
ScrollingLeable.Visible = false;
}

Related

SignalR send duplicate message to same user n times n is number of users connected .NetCore

I have SignalR ASP.NET Core project and trying to send message tp specific user which I manage to do so. The problem is same message send n time n=number of tabs or connections when ever there is change from database it send notification to that certain User but duplicate the message.
public class MessageHub: Hub
{
public MessageHub(IConfiguration cc, IHubContext<MessageHub> _mess, UserManager<ApplicationUser> rep)
{
mess = _mess;
_conf = cc;
_usermanager = rep;
RegisterNotification();
}
public void RegisterNotification()
{
using (SqlConnection con = new SqlConnection(conStr))
{
SqlCommand cmd = new SqlCommand(sqlCommand, con);
if (con.State != System.Data.ConnectionState.Open)
{
con.Open();
}
cmd.Notification = null;
SqlDependency sqlDep = new SqlDependency(cmd);
sqlDep.OnChange += sqlDep_OnChange;
using (SqlDataReader reader = cmd.ExecuteReader())
{
// nothing need to add here now
}
}
}
static int count = 1;
private void sqlDep_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change )
{
SqlDependency sqlDep = sender as SqlDependency;
sqlDep.OnChange -= sqlDep_OnChange;
mess.Clients.User("64ed09d7-255f-4aae-a25f-7a50e59943b4").SendAsync("abc", "hello"+count);
count += 1;
RegisterNotification();
}
}
}
as you have mentioned, the problem is RegisterNotification is being called everytime an instance of MessageHub is created. Instead of this, you can create background service and register to SqlDependency there and send the events using IHubContext. And after every notification, you call RegisterNotification again, which might cause the duplication as well.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/hosted-services
https://learn.microsoft.com/en-us/aspnet/core/signalr/hubcontext
I haven't tested this code, but here is an example:
public class EventBroadcaster : IHostedService
{
private readonly IHubContext<MessageHub> _hubContext;
private readonly string _connectionString;
public EventBroadcaster(
IConfiguration configuration,
IHubContext<MessageHub> hubContext)
{
_hubContext = hubContext;
_connectionString = // Get Connection String from configuration
}
public Task StartAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Started event broadcasting service");
RegisterNotification();
return Task.CompletedTask;
}
public void RegisterNotification()
{
using (SqlConnection con = new SqlConnection(_connectionString))
{
SqlCommand cmd = new SqlCommand(sqlCommand, con);
if (con.State != System.Data.ConnectionState.Open)
{
con.Open();
}
cmd.Notification = null;
SqlDependency sqlDep = new SqlDependency(cmd);
sqlDep.OnChange += sqlDep_OnChange;
using (SqlDataReader reader = cmd.ExecuteReader())
{
// nothing need to add here now
}
}
}
static int count = 1;
private async void sqlDep_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change )
{
SqlDependency sqlDep = sender as SqlDependency;
sqlDep.OnChange -= sqlDep_OnChange;
await _hubContext.Clients.User("64ed09d7-255f-4aae-a25f-7a50e59943b4").SendAsync("abc", "hello"+count);
count += 1;
}
}
public Task StopAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Event Broadcasting Service is stopping.");
// TODO: Stop listening to SqlDependency notifications
return Task.CompletedTask;
}

WPF Enabling a button with SQL condition

I want to make button enabled, depending on what data is in SQL table. I made table with boolean type column and now I want WPF to read it and make button enabled or disabled. I made class for connection:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Windows;
using System.Data.SqlClient;
using System.Configuration;
namespace WpfCalendar.Classes
{
class SQLconnection
{
public static string GetConnectionStrings()
{
string strConString = ConfigurationManager.ConnectionStrings["conString"].ToString();
return strConString;
}
public static string sql;
public static SqlConnection con = new SqlConnection();
public static SqlCommand cmd = new SqlCommand("",con);
public static SqlDataReader rd;
public static DataTable dt;
public static SqlDataAdapter da;
public static void openConnection()
{
try
{
if (con.State == ConnectionState.Closed)
{
con.ConnectionString = GetConnectionStrings();
con.Open();
}
}
catch (Exception ex)
{
MessageBox.Show("Brak połaczenia" + Environment.NewLine + ex.Message.ToString(), "C# WPF connect to SQL server", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
public static void closeConnection()
{
try
{
if(con.State == ConnectionState.Open)
{
con.Close();
}
}
catch(Exception)
{
}
}
}
}
And my window xaml.cs
public partial class Kalendarz : Window
{
public Kalendarz()
{
InitializeComponent();
}
private void Sprawdzanko1(object sender, RoutedEventArgs e)
{
DateTime dt = DateTime.Now;
bool klikniente;
SQLconnection.openConnection();
SQLconnection.cmd.CommandText = SQLconnection.sql;
SQLconnection.sql = "Select [Otwarte] FROM Okienka WHERE Dzien LIKE '1';";
SQLconnection.cmd.CommandType = CommandType.Text;
SQLconnection.da = new SqlDataAdapter(SQLconnection.cmd);
klikniente = (bool)SQLconnection.cmd.ExecuteScalar();
if (klikniente == true && dt.Day == 1 && dt.Month == 12)
{
b1.IsEnabled = true;
}
else
{
b1.IsEnabled = false;
}
SQLconnection.closeConnection();
}
I'm making a WPF advent calendar so the idea is to check if the button was clicked before and if date is correct. But the buttons don't react an I'm pretty sure the code isn't even executed...
Ok so I think I got it. It works so I'm fine with it :D
private void Sprawdzanko1()
{
bool klikniente;
using (SQLconnection.con)
{
SQLconnection.openConnection();
SqlCommand cmd = new SqlCommand("Select [Otwarte] FROM Okienka WHERE Dzien LIKE '1';", SQLconnection.con);
klikniente = (bool)cmd.ExecuteScalar();
SQLconnection.closeConnection();
}
if (klikniente == false && dt.Day == 1 && dt.Month == 12)
{
b1.IsEnabled = true;
}
else
{
b1.IsEnabled = false;
}
}
And then you call Sprawdzanko1();

Error to connecting to my database (MySQL, C#)

This did not worked when I ran the program!
using MySql.Data;
using MySql.Data.MySqlClient;
namespace MySQL
{
class SqlConnection
{
public SqlConnection() { }
~SqlConnection() { }
private string strConnection = "Server=localhost;Database=database;Port=3306;User ID=root;Password=";
private MySqlConnection connection;
public void OpenConnection()
{
connection = new MySqlConnection();
connection.Open();
}
public void CloseConnection()
{
connection.Close();
connection.Dispose();
}
public string StrConnection
{
set
{
StrConnection = value;
}
get
{
return StrConnection;
}
}
}
}
but it is not working!
ERROR : host 'xxx' is not allowed to connect to this MariaDB sever!
You don't use the connection string property strConnection, when you initialize your connection. Try:
public void OpenConnection()
{
connection = new MySqlConnection(strConnection);
connection.Open();
}

C# Update label real time from database

What is a good way to update a label on your winforms by fetching result from the database. So all users get the update real time instead for starting the winform over to get the update.
public partial class labelControl : UserControl
{
public labelControl()
{
InitializeComponent();
updateLabel();
}
private void updateLabel()
{
using (Database.sqlConnection = new SqlConnection(Database.connectionString))
{
Database.sqlConnection.Open();
string selectQuery = "SELECT * FROM Information";
using (SqlCommand sqlCommand = new SqlCommand(selectQuery, Database.sqlConnection))
{
using (SqlDataReader sqlReader = sqlCommand.ExecuteReader())
{
if (sqlReader.HasRows)
{
while (sqlReader.Read())
{
label1.Text = sqlReader["Text"].toString();
}
}
}
}
}
}
}
try this, add a Task run at background, and sleep thread for interval of refresh.
public labelControl()
{
InitializeComponent();
if (!this.DesignMode)
{
RefreshLabel();
}
}
private async void RefreshLabel()
{
await Task.Run(() => {
while (true)
{
try
{
using (Database.sqlConnection = new SqlConnection(Database.connectionString))
{
Database.sqlConnection.Open();
string selectQuery = "SELECT Text FROM Information WHERE ID = (SELECT MAX(ID) FROM Information)"; // you probably want the latest value
using (SqlCommand sqlCommand = new SqlCommand(selectQuery, Database.sqlConnection))
{
using (SqlDataReader sqlReader = sqlCommand.ExecuteReader())
{
if (sqlReader.HasRows)
{
while (sqlReader.Read())
{
ChangeLabelText(sqlReader["Text"].ToString());
}
}
}
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
System.Threading.Thread.Sleep(500); // time to sleep thread
}
});
}
private void ChangeLabelText(string value)
{
if (label1.InvokeRequired)
{
label1.Invoke(new Action<string>(ChangeLabelText), value);
return;
}
label1.Text = value;
}
public partial class labelControl : UserControl
{
private const short interval = 5;
private Timer timer;
public labelControl()
{
InitializeComponent();
timer = new Timer()
timer.Interval = interval * 1000; //time to refresh the label in seconds
timer.Tick += updateLabel;
timer.Start();
}
private void updateLabel()
{
try
{
using (Database.sqlConnection = new SqlConnection(Database.connectionString))
{
Database.sqlConnection.Open();
string selectQuery = "SELECT Text FROM Information WHERE ID = (SELECT MAX(ID) FROM Information)"; // you probably want the latest value
using (SqlCommand sqlCommand = new SqlCommand(selectQuery, Database.sqlConnection))
{
using (SqlDataReader sqlReader = sqlCommand.ExecuteReader())
{
if (sqlReader.HasRows)
{
while (sqlReader.Read())
{
label1.Text = sqlReader["Text"].ToString();
}
}
}
}
}
}
catch()
{
//do nothing
}
}
}
with this solution you are calling your database every 5 seconds and refreshing the text of your label with the latest value from your table in database

Thread Safe Data Access Object C#

I'm trying to make a thread safe Data Access Layer (kind of like a SQL Data Client wrapper). What are some steps I should be making to make this thread safe, while maximizing performance.
For example, if i add a lock on the sqlConn before it closes the connection (since it implements IDisposable); what if the connection is in the middle of a transaction or query?
In summary, I'm trying to accomplish a thread-safe solution; but at the same time, I do not want to risk any critical exceptions, or any delays. Is there any way I can prioritize the closing thread?
public class SQLWrapper : IDisposable
{
private SqlConnection _sqlConn;
public SQLWrapper(string serverName_, string dbName_)
{
SqlConnectionStringBuilder sqlConnSB = new SqlConnectionStringBuilder()
{
DataSource = serverName_,
InitialCatalog = dbName_,
ConnectTimeout = 30,
IntegratedSecurity = true,
};
sqlConnSB["trusted_connection"] = "yes";
this.start(sqlConnSB.ConnectionString);
}
public SQLWrapper(string connString_)
{
this.start(connString_);
}
private void start(string connString_)
{
if (string.IsNullOrEmpty(connString_) == true)
throw new ArgumentException("Invalid connection string");
**lock (this._sqlConn)**
{
this._sqlConn = new SqlConnection(connString_);
this._sqlConn.Open();
}
}
private void CloseConnection()
{
**lock (this._sqlConn)**
{
this._sqlConn.Close();
this._sqlConn.Dispose();
this._sqlConn = null;
}
}
}
The step you should do is:
NOT making it thread safe.
Simple.
Every thread should have it's own copy, with locking / synchronization happening on the database.
THen it will also scale across computers.
This is the standard approach for the last 20 years or so.
So, every thread creates a new SqlWrapper and everything is fine.
The database performs connection pooling for you; lean on it as much as you can. You really shouldn't require locking.
Option 1.
SqlConnection is not encapsulated by the DAO class; appropriate using structures and storage of the connection string is required at the method level.
public class SomeDAO
{
private readonly string _connectionString;
public SomeDAO(string dsn)
{
_connectionString = dsn;
}
public IEnumerable<AssetVO> DoWork()
{
const string cmdText = "SELECT [AssetId] FROM [dbo].[Asset]";
using (var conn = new SqlConnection(_connectionString))
{
conn.Open();
using (var cmd = new SqlCommand(cmdText, conn))
using (var dr = cmd.ExecuteReader())
{
while (dr.Read())
{
yield return new AssetVO
{
AssetId = Guid.Parse(dr["AssetId"].ToString()),
};
}
}
}
}
}
Option 2.
The SqlConnection is a class member; it's state is carefully maintained by helper methods. Using syntax is used for SqlDataReader and SqlCommand.
public class SomeDAO : IDisposable
{
#region backing store
private readonly SqlConnection _connection;
#endregion
public SomeDAO(string dsn)
{
_connection = new SqlConnection(dsn);
}
public SqlConnection OpenConnection()
{
if (_connection.State != ConnectionState.Closed)
_connection.Open();
return _connection;
}
public void CloseConnection()
{
if (_connection.State != ConnectionState.Closed)
_connection.Close();
}
public IEnumerable<AssetVO> DoWork()
{
const string cmdText = "SELECT [AssetId] FROM [dbo].[Asset]";
try
{
using (var cmd = new SqlCommand(cmdText, OpenConnection()))
using (var dr = cmd.ExecuteReader())
{
while (dr.Read())
{
yield return new AssetVO
{
AssetId = Guid.Parse(dr["AssetId"].ToString()),
};
}
}
}
finally
{
CloseConnection();
}
}
#region Implementation of IDisposable
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
/// <filterpriority>2</filterpriority>
public void Dispose()
{
_connection.Dispose();
}
#endregion
}
Both solutions survive a threaded test without the need for explicit locking.
private static volatile bool _done;
private static void Main()
{
#region keyboard interrupt
ThreadPool.QueueUserWorkItem(delegate
{
while (!_done)
{
if (!Console.KeyAvailable) continue;
switch (Console.ReadKey(true).Key)
{
case ConsoleKey.Escape:
_done = true;
break;
}
}
});
#endregion
#region start 3 threads in the pool
ThreadPool.QueueUserWorkItem(DatabaseWorkerCallback);
ThreadPool.QueueUserWorkItem(DatabaseWorkerCallback);
ThreadPool.QueueUserWorkItem(DatabaseWorkerCallback);
#endregion
Thread.Sleep(Timeout.Infinite);
}
private static void DatabaseWorkerCallback(object state)
{
Console.WriteLine("[{0}] Starting", Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(1000);
while (!_done)
{
using (var dao = new SomeDAO(Properties.Settings.Default.DSN))
{
foreach (var assetVo in dao.DoWork())
Console.WriteLine(assetVo);
}
}
Console.WriteLine("[{0}] Stopping", Thread.CurrentThread.ManagedThreadId);
}

Categories

Resources