I'm having an issue when connecting to a remote host. I am able to connect to my local server with a copy of the database.
I'm trying to connect to the XenForo DB on my web host and get some information. All is working on localhost.
private static MySqlConnection _connection =
new MySqlConnection("Server=ip; database=ls-v_forum; UID=ls-v_forum; password=pass");
public static int? FetchUserId(string emailoruser)
{
MySqlCommand userCommand = new MySqlCommand("SELECT * FROM xf_user WHERE username='" + emailoruser + "'", _connection);
MySqlCommand emailCommand = new MySqlCommand("SELECT * FROM xf_user WHERE email='" + emailoruser + "'", _connection);
_connection.OpenAsync();
}
That's the code and it's throwing this error
Connection must be valid and open.
at MySql.Data.MySqlClient.ExceptionInterceptor.Throw(Exception exception)
at MySql.Data.MySqlClient.MySqlCommand.CheckState()
at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior
behavior)
EDIT
public int? FetchUserId(string emailoruser)
{
using (var _connection = new MySqlConnection("server=ip; database=ls-v_forum; UID=ls-v_forum; password=pass"))
{
MySqlCommand userCommand = new MySqlCommand("SELECT * FROM xf_user WHERE username='" + emailoruser + "'", _connection);
MySqlCommand emailCommand = new MySqlCommand("SELECT * FROM xf_user WHERE email='" + emailoruser + "'", _connection);
_connection.Open();
MySqlDataReader userReader = userCommand.ExecuteReader();
int? userId = null;
while (userReader.Read())
{
userId = userReader.GetInt32("user_id");
}
userReader.Close();
if (userId == null || userId == 0)
{
MySqlDataReader emailReader = emailCommand.ExecuteReader();
while (emailReader.Read())
{
userId = emailReader.GetInt32("user_id");
}
emailReader.Close();
}
_connection.Close();
return userId;
}
}
MySql.Data.MySqlClient.MySqlException (0x80004005): Unable to connect to any
of the specified MySQL hosts.
at MySql.Data.MySqlClient.NativeDriver.Open()
at MySql.Data.MySqlClient.Driver.Open()
at MySql.Data.MySqlClient.Driver.Create(MySqlConnectionStringBuilder
settings)
at MySql.Data.MySqlClient.MySqlPool.CreateNewPooledConnection()
at MySql.Data.MySqlClient.MySqlPool.GetPooledConnection()
at MySql.Data.MySqlClient.MySqlPool.TryToGetDriver()
at MySql.Data.MySqlClient.MySqlPool.GetConnection()
at MySql.Data.MySqlClient.MySqlConnection.Open()
I didn't attempt to troubleshoot your connection command, but the following works for me when connecting to a SQL DB on a remote machine
You can provide the machine name even if it is the local machine, so the code below will work if the program is running on the same machine as the database or if the program is running on one machine and the database is on another, so long as the two machines are networked AND the account you're running the program under has access to the machine and instance and database.
Please note in example below, the "default" instance name (MSSQLSERVER) was used when SQL was installed. When the DB instance name is the default name, then you must not provide an instance name explicitly (you'll get an error if you do). The only time you provide an instance name explicitly is when it is not the default instance name. The code below can handle either scenario (by setting dbInstanceName variable to "" or an instance name, e.g. "\SQLEXPRESS"). See S.O. SQL Server: How to find all localdb instance names. When it doubt, try an empty instance name and a name you believe to be the instance name to see what works.
string databaseMachineName = "machine_name";
string databaseInstanceName = "";
string dbName = "database_name";
using (SqlConnection sqlConnection = new SqlConnection("Data Source=" + databaseMachineName + databaseInstanceName + "; Initial Catalog=" + dbName + "; Integrated Security=True;Connection Timeout=10"))
{
.
.
.
}
I'm having an issue when connecting to a remote host.
Not necessarily. According to the error, the issue isn't that you can't connect. It's that you're trying to use a connection that isn't connected:
Connection must be valid and open.
Specifically where you execute a command:
MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
Which isn't in the code you're showing. However, there are a couple of fundamental mistakes that are in the code you're showing which would easily lead to an error like this:
1. Using a static shared connection object.
This is a famously bad idea. We've probably all tried it, and we've probably all run into issues exactly like this one. The underlying system is pretty efficient at creating/pooling/using/disposing database connections. Don't try to optimize for it. Instead, you should create/use/dispose your connections in as small a scope as possible. For example:
using (var connection = new MySqlConnection(SOME_CONNECTION_STRING))
{
var userCommand = new MySqlCommand(SOME_COMMAND_STRING);
// use the command, get the data you need from it
}
// leave the context of the database and return to business logic, UI, etc.
This is because keeping complex things like database connections synchronized is hard, and keeping connections open is expensive. Let the underlying system open/pool/close connections.
2. Not awaiting an async operation.
What would happen here?:
connection.OpenAsync();
userCommand.ExecuteNonQuery();
An error. Because the code didn't await the asynchronous operation, so the connection isn't open when you're trying to use it. Either don't use the asynchronous operation:
connection.Open();
userCommand.ExecuteNonQuery();
or await it:
await connection.OpenAsync();
userCommand.ExecuteNonQuery();
(And obviously make the containing method async, and its callers should await it, etc.) But definitely don't try to use a connection before it's had a chance to open.
3. (Unrelated, but still important) Your code is vulnerable to SQL injection.
SQL injection happens right here:
"SELECT * FROM xf_user WHERE username='" + emailoruser + "'"
Where did emailoruser come from? Was it user input? Was it a value pulled from data which was previously provided by a user? How trustworthy is it? What this string-concatenation approach does is allow any user to execute any SQL code they want on your database. Instead, use query parameters and treat user input as values instead of as executable code.
Related
I am developing an asp.net web application and I am trying to add a user xp system to it. I have a SQL Server database connected to it and I am trying to make a function that will give 5 experience points to the user.
I queried to the user that is logged in, accessed the user_xp column, and I am trying to add +5 to the old session variable for xp, then send that back into the database to be stored. Here is my code, I am not sure what is wrong with it.
void generateXp()
{
try
{
SqlConnection con = new SqlConnection(strcon);
if (con.State == ConnectionState.Closed)
{
con.Open();
}
SqlCommand cmd = new SqlCommand("UPDATE member_master_tbl SET user_xp = #user_xp WHERE " +
"user_name = '" + Session["username"].ToString().Trim() + "'", con);
int xp = 5;
int current_xp = Convert.ToInt32(Session["user_xp"]);
int new_xp = xp + current_xp;
string new_xp2 = Convert.ToString(new_xp);
cmd.Parameters.AddWithValue("user_xp", new_xp2);
}
catch (Exception ex)
{
}
}
Try renaming the SQL parameter to #user_xp.
cmd.Parameters.AddWithValue("#user_xp", new_xp2);
I don't have an accessible database to test. Also, you need to add the command to execute the query at the end.
cmd.ExecuteNonQuery()
That being said, it's a good practice to learn to separate DB queries to stored procedures or functions.
As others noted, you simply forgot to do a execute non query to run the command that you setup.
However, you can write things this way. You don't mention or note what the data type the experience points column is - I assumed "int".
So, your code block can be written this way:
using (SqlCommand cmd = new SqlCommand("UPDATE member_master_tbl SET user_xp = #user_xp WHERE user_name = #user",
new SqlConnection(strcon)))
{
cmd.Parameters.Add("#user_xp", SqlDbType.Int).Value = 5 + Session("user_xp");
cmd.Parameters.Add("#user", SqlDbType.NVarChar).Value = Session("username");
cmd.Connection.Open();
cmd.ExecuteNonQuery();
}
note how the command object has a connection object (so we don't need a separate one).
And while several people here "lamented" the string concentration to build the sql and warned about sql injection?
Actually, the introduction of # parameters for both values cleans up the code. So you get nice parameters - nice type checking, and you don't have to remember to add/use/have things like quotes around teh string, but not for numbers.
And I let .net cast the number expression from session() - this also likely is ok.
Also the "using block" also correctly cleans up the command object and also the connection object - so the using block is a good idea here.
I have tested this application many times, but all of a sudden it threw an error like this, while running the app:
'''System.Data.SqlClient.SqlException: 'The server principal "domain\user" is not able to access the database "db2" under the current security context.'
'''
The database name "db2" is not the name of the database referenced inside the application.
The place in the application where it threw the error was here:
private List<DBInvoiceModel> GetInvoiceRecords(int orderNumber)
{
// "vsView"
var dbConnection = new SqlConnection("Data Source=domain;Initial Catalog=Test;Integrated Security=true");
dbConnection.Open();
var sqlCmd = dbConnection.CreateCommand();
sqlCmd.CommandText = #"SELECT
[ItemID]
,[TranNo]
,[STaxAmt]
,[TranAmt]
,[Status]
,[EDITranNum]
,[QtyShipped]
,[FreightAmt]
,[TrackingNumber]
,[ItemPrice]
FROM [Test].[dbo].[vsView]
WHERE EDITranNum = '" + orderNumber.ToString() + "'";
var reader = sqlCmd.ExecuteReader();
List<DBInvoiceModel> result = new List<DBInvoiceModel>();
while (reader.Read())
{
I checked with the IT Dept, they said no permissions changes have been made. Any ideas on how I could re-code this or refresh data connection? I have searched the Solution Explorer for the name of the database, in this case, "db2", however, it does not appear anywhere in the project.
I HAVE used the database referenced only in creating SSRS reports.
I have a WebService that updates my access table from some terminals (10).
When I try to update I get this error from the error log:
Could not Update; Currently locked
Some terminals succeed and some do not.
I update like this:
using (Conn = new OleDbConnection(Work_Connect))
{
Conn.Open();
foreach (DataRow R in ds.Tables["MyCount"].Rows)
{
U_ID = ID;
U_Bar = R["Bar"].ToString().Trim();
U_Qty = R["Qty"].ToString().Trim();
U_Des = R["Des"].ToString().Trim();
SQL = "INSERT INTO MyTbl(ID,Bar,Qty,Des)VALUES('";
SQL += Convert.ToInt32(ID) + "','" + U_Bar + "','" + Convert.ToDouble(U_Qty) + "','" + U_Des + "')";
OleDbCommand Cmd2 = new OleDbCommand(SQL, Conn);
Cmd2.CommandText = SQL;
Cmd2.ExecuteNonQuery();
}
}
GC.Collect();
return true;
MsAccess has serious drawbacks for multi-user update. The Jet engine is not a database server, and will manage concurrence based on file system locking. If your problem is with a web service, I'd move the update to the server part, and implement queuing of simultaneous requests there. Thus, only the server, one process, will have access to the Access data. The other option is to use a real database server that will do that work for you. SQL Server Express is the usual option because it's easy to integrate, it's free as in beer, and is solid.
Also, if your problem happens always from the same terminals, that is, some terminals can never update anything, check the file access rights of these terminals' users to the database file, the lock file, and the database and lock file directory. Write rights are required for all of them.
Suggestions:
Convert your query to a parameterized query to avoid any potential strangeness with quoting. (You are converting text to numbers and then enclosing them in single-quotes in the SQL statement. That makes no sense.)
Don't force garbage collection on each call. According to the MSDN article here: "It is possible to force garbage collection by calling Collect, but most of the time, this should be avoided because it may create performance issues."
Try something like this instead:
using (Conn = new OleDbConnection(Work_Connect))
{
Conn.Open();
foreach (DataRow R in ds.Tables["MyCount"].Rows)
{
U_ID = ID;
U_Bar = R["Bar"].ToString().Trim();
U_Qty = R["Qty"].ToString().Trim();
U_Des = R["Des"].ToString().Trim();
SQL = "INSERT INTO MyTbl (ID,Bar,Qty,Des) VALUES (?,?,?,?)";
using(OleDbCommand Cmd2 = new OleDbCommand(SQL, Conn))
{
// Cmd2.CommandText = SQL; redundant, the 'new' set the .CommandText
Cmd2.Parameters.AddWithValue("?", Convert.ToInt32(ID));
Cmd2.Parameters.AddWithValue("?", U_Bar);
Cmd2.Parameters.AddWithValue("?", Convert.ToDouble(U_Qty));
Cmd2.Parameters.AddWithValue("?", U_Des);
Cmd2.ExecuteNonQuery();
}
}
Conn.Close();
}
// GC.Collect(); // disabled for test purposes
return true;
I have a problem with a threaded Client/Server application, I have a serversid that has a Access DB, and with one thread for each client, but I get a problem if both client threads asks to open the DB at the same time. Is there any way to check if the DB is in use (I know I can have a varible and keep controlling/setting that, but would like to avoid that. Here is an example connection
String connectionString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + dbPath + "'";
OleDbConnection connection = new OleDbConnection(connectionString);
OleDbCommand command;
connection.Open();
command = new OleDbCommand("UPDATE Client SET Online = " + online)
command.ExecuteNonQuery();
connection.Close();
Would really like some help!
/Nick
Per this http://www.connectionstrings.com/access-2007 you can set Exclusive=1 in connection string to grant that only one connection can use this database. All another trying will fail.
I have a piece of code that creates an SQL Server Express 2008 in runtime, and then tries to connect to it to execute a database initialization script in Transact-SQL. The code that creates the database is the following:
private void CreateDatabase()
{
using (var connection = new SqlConnection(
"Data Source=.\\sqlexpress;Initial Catalog=master;" +
"Integrated Security=true;User Instance=True;"))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText =
"CREATE DATABASE " + m_databaseFilename +
" ON PRIMARY (NAME=" + m_databaseFilename +
", FILENAME='" + this.m_basePath + m_databaseFilename + ".mdf')";
command.ExecuteNonQuery();
}
}
}
The database is created successfully. After that, I try to connect to the database to run the initialization script, by using the following code:
private void ExecuteQueryFromFile(string filename)
{
string queryContent = File.ReadAllText(m_filePath + filename);
this.m_connectionString = string.Format(
#"Server=.\SQLExpress; Integrated Security=true;Initial Catalog={0};", m_databaseFilename);
using (var connection = new SqlConnection(m_connectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = queryContent;
command.CommandTimeout = 0;
command.ExecuteNonQuery();
}
}
}
However, the connection.Open() statement fails, throwing the following exception:
Cannot open database "TestData"
requested by the login. The login
failed. Login failed for user
'MYDOMAIN\myusername'.
I am completely puzzled by this error because the account I am trying to connect with has sysadmin privileges, which should allow me to connect any database (notice that I use a connection to the master database to create the database in the first place).
Is there a reason you specify User Instance=True when you create it but not when you try to connect to it?
When you create it after connecting with User Instance, it will create the database files but does not attach it to your actual instance. You'll either have to not specify User Instance=True in the first connection string or add it to the second and specify the database file to use.
Is the user you are logging with have rights to the database 'TestData'?
If not grant the user the privileges required.
I am not sure if this means anything, but in your first create you are connecting to server
.\\sqlexpress
The second one is
.\SQLExpress
You'll need to issue a CREATE USER command (see: http://msdn.microsoft.com/en-us/library/ms173463.aspx) after creating the database but before trying to open a connction to that database.
For example:
CREATE USER 'MYDOMAIN\myusername' FOR LOGIN 'MYDOMAIN\myusername'