Unable to connect to local database SQL - c#

I have a problem with my local database made with SQL Server (Local DB).
I can connect to the database on my computer but if I try to another computer, I get this error message:
I want a local database to store data, I don't need a server to manage the database.
This is my connection string:
`<connectionStrings>
<add name="stocksDB" connectionString="Data Source= (LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\myDB.mdf;Integrated Security=True;" providerName="System.Data.SqlClient"/>
</connectionStrings>`
I have included the "SQL Server 2012 Express LocalDB" in prerequisites.
What did I do wrong?

If you have two computers (lets say their machine names are "pc_a" and "pc_b" that are networked together and the program is running on computer "pc_a" and the database resides on computer "pc_b", then your connect string needs to include the machine name for computer "pc_b".
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 the error you showed if you do). The only time you provide an instance name explicitly is when it it 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 = "pc_b";
string databaseInstanceName = "";
string dbName = "stocksDb";
using (SqlConnection sqlConnection = new SqlConnection("Data Source=" + databaseMachineName + databaseInstanceName + "; Initial Catalog=" + dbName + "; Integrated Security=True;Connection Timeout=10"))
{
.
.
.
}

Solved! The problem was the wrong SQL Server version on the other computer. On my main computer I have SQL Server 2014 and on the other one the 2012 version so the "database instance name" was different. Thanks to #Nova Sys Eng for the input!
Now I changed my connection string:
First of all I used a code to retrieve all the SQL server instances installed on the computer as explained on the link posted by Nova Sys Eng.
var instances = GetLocalDBInstances();
var connString= string.Format("Data Source= (LocalDB)\\{0};AttachDbFilename=|DataDirectory|\\myDB.mdf;Integrated Security=True;",instances[0]);
internal static List<string> GetLocalDBInstances()
{
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "cmd.exe";
p.StartInfo.Arguments = "/C sqllocaldb info";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
// p.WaitForExit();
// Read the output stream first and then wait.
string sOutput = p.StandardOutput.ReadToEnd();
p.WaitForExit();
//If LocalDb is not installed then it will return that 'sqllocaldb' is not recognized as an internal or external command operable program or batch file.
if (sOutput == null || sOutput.Trim().Length == 0 || sOutput.Contains("not recognized"))
return null;
string[] instances = sOutput.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
List<string> lstInstances = new List<string>();
foreach (var item in instances)
{
if (item.Trim().Length > 0)
lstInstances.Add(item);
}
return lstInstances;
}

Related

How to backup a database in WPF with C# and SQL Server? [duplicate]

This question already has answers here:
Backup Permissions
(5 answers)
Closed 1 year ago.
I'm trying to back up my database using this C# code How to backup and restore SQL Server in WPF with C# and Entity Framework
private static void CreateBackup(string databaseName, string backupFilePath)
{
GlobalConfig gb = new GlobalConfig();
string connectionString = gb.GetConnectionString();
backupFilePath = backupFilePath + "\\" + databaseName + ".bak";
backupFilePath = #""+backupFilePath;
var backupCommand = "BACKUP DATABASE #databaseName TO DISK = #backupFilePath";
using (var conn = new SqlConnection(connectionString))
using (var cmd = new SqlCommand(backupCommand, conn))
{
conn.Open();
cmd.Parameters.AddWithValue("#databaseName", databaseName);
cmd.Parameters.AddWithValue("#backupFilePath", backupFilePath);
cmd.ExecuteNonQuery();
}
}
CreateBackup("Test","C:\Desktop\Backup\\Test.bak");
But I got this error :
Cannot open backup device 'C:\Desktop\Backup\Test.bak'. Operating system error 5(Access is denied.).
What I'm doing wrong with this code?
How can I fix this error?
The SQL Server process typically does not run with the permissions of the currently logged in user, therefore it cannot access the users desktop (nor most of the folders of the user or any network folders). It is not possible to freely choose the folder for the backup.
Your best solution is to export to a folder where the server process has access to (i.e. the system temp folder) and then copy the backup from there to wherever you want it.
private static void CreateBackup(string databaseName, string backupFilePath)
{
GlobalConfig gb = new GlobalConfig();
string connectionString = gb.GetConnectionString();
// Create the backup in the temp directory (the server should have access there)
var backup = Path.Combine(Path.GetTempPath(), "TemporaryBackup.bak");
var backupCommand = "BACKUP DATABASE #databaseName TO DISK = #backup";
using (var conn = new SqlConnection(connectionString))
using (var cmd = new SqlCommand(backupCommand, conn))
{
conn.Open();
cmd.Parameters.AddWithValue("#databaseName", databaseName);
cmd.Parameters.AddWithValue("#backup", backup);
cmd.ExecuteNonQuery();
}
File.Copy(backup, backupFilePath); // Copy file to final location
}
I have successfully backed up SQL Server databases using Microsoft.SqlServer.Management.Smo.Backup, might want to try that. Mine was in VB years ago but it is still working today. Here is the VB code if it helps:
Dim mySourceServer As New Server(My.Settings.SQLInstance)
Dim bkpDBFullWithCompression As New Backup()
' Specify whether you want to back up database or files or log
Me.Cursor = Cursors.WaitCursor()
bkpDBFullWithCompression.Action = BackupActionType.Database
' Specify the name of the database to back up
bkpDBFullWithCompression.Database = _sBackupDatabaseName
bkpDBFullWithCompression.CompressionOption = BackupCompressionOptions.[On]
bkpDBFullWithCompression.Devices.AddDevice(_sBackupFilePath, DeviceType.File)
bkpDBFullWithCompression.BackupSetName = _sBackupDatabaseName + " database Backup - Compressed"
bkpDBFullWithCompression.BackupSetDescription = _sBackupDatabaseName + " database - Full Backup"
Try
bkpDBFullWithCompression.SqlBackup(mySourceServer)
Catch ex As SmoException
blSuccess = False '
Me.Cursor = Cursors.Default
End Try
This solution ( Check Local System account instead of This account ) worked for me, but I didn't have any idea if it's a good solution for security or no.
You can find the LogOn tab setting under this :
Services -> SQL Server -> Properties -> Log on

LocalDB connections visible in SQL management studio

In my unit tests, I'm using a SQL Server LocalDB database. You could be nit picky and say that because of that fact it's not unit tests but integration tests and you would be right, but the point is that I am using the MSTest Framework to run those tests. Every test is copying an existing database and running their one test on this database.
private NAMETestSystem([CallerMemberName] string testCase = null)
{
this.destinationDirectory = Path.Combine(Directory.GetCurrentDirectory(), testCase ?? "Undefined_" + Guid.NewGuid().ToString("N"));
var connectionString = $"Data Source=(LocalDB)\\MSSQLLocalDB; Integrated Security = True; AttachDbFilename ={Path.Combine(this.destinationDirectory, "NAMEIntegrationTest.mdf")}";
var entityFrameworkData = $"metadata=res://*/NAME.csdl|res://*/NAME.ssdl|res://*/NAME.msl;provider=System.Data.SqlClient;provider connection string=\"{connectionString}\"";
// [...]
Copy(SourceDirectory, this.destinationDirectory);
My "problem" is that each of those copies pops up in my SQL Server management studio. All 100+ or them. I don't need them there. They don't exist anymore. And to make things worse, you cannot batch-detach... I have to press Del+Enter about 150 times just to clear that window up.
Is there a way to not have my temporary local db instances appear in my SQL server management studio?
Maybe special way to close or dispose, something in the connection string I can set? Or maybe a way to detach all of them at the same time in management studio?
So in the end, what I did and what is working fine for now is this:
public void Dispose()
{
// disposing other stuff
// sql db
if (Directory.Exists(this.destinationDirectory))
{
DetachDatabase(this.connectionString);
Directory.Delete(this.destinationDirectory, true);
}
}
public static void DetachDatabase(string connectionString)
{
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
using (var command = connection.CreateCommand())
{
var sql = "DECLARE #dbName NVARCHAR(260) = QUOTENAME(DB_NAME());\n" +
"EXEC('ALTER DATABASE ' + #dbName + ' SET OFFLINE WITH ROLLBACK IMMEDIATE;');\n" +
"EXEC('exec sp_detach_db ' + #dbName + ';');";
command.CommandText = sql;
command.ExecuteNonQuery();
}
}
}
Might not be the prettiest solution, but at least it keeps my sanity intact while the number of tests (and number of databases) rises.

Can`t Permit Microsoft.SqlServer.Management.Smo.Server via database permission

Can anyone plz explain which special permission require for doing Microsoft.SqlServer.Management.Smo.Server connection via server and client both end.
i have following scenario.
server PC With Sql Server 2012 database
client PC With Only Program Which will connect database of server
i successfully got the db connection via visual stdio sqlconnectin class of remote database
but when i use Microsoft.SqlServer.Management.Smo.Server it will thrwo error for permission
can anyone help?
var connectionString = ConfigurationManager.ConnectionStrings["AppConString"].ConnectionString;
SqlConnectionStringBuilder sqlconstrbldr = new SqlConnectionStringBuilder(connectionString.ToString());
ServerConnection connection = new ServerConnection();
Microsoft.SqlServer.Management.Smo.Server sqlServer = new Microsoft.SqlServer.Management.Smo.Server(sqlconstrbldr.DataSource);
ServerName = sqlconstrbldr.DataSource;
foreach (Microsoft.SqlServer.Management.Smo.Database dbServer in sqlServer.Databases)
{
if (dbServer.Name.StartsWith("AMCS"))
{
string year = dbServer.Name;
year = year.Substring(4);
string Fyear = year.Substring(0, 2);
string Lyear = year.Substring(2);
Fyear = "20" + Fyear;
Lyear = "20" + Lyear;
string dbYear = Fyear + " - " + Lyear;
cmbDbYear.Items.Add(dbYear);
}
}
Explaination
cmbDbYear is Just Combobox in which all database names will be bonded.
MY Question is That What Remission Needed for SQL Server Management Object (Microsoft.SqlServer.Smo) must required for SQL Server Database user to successfully perform operation
i can Do Normal Database Operation currently but want also SQL Server Management Object (Microsoft.SqlServer.Smo) on database.

How to get SQL JobStep connection strings

After I get the server jobs and I got each job steps I want to get the connection string related to each step as you could find it while opening SQL management studio in jobs like this:
is there is a suitable way to get the connection strings for each package by C# code?
ServerConnection conn = new ServerConnection("localhost");
//new SqlConnection("data source=localhost;initial catalog=CPEInventory_20101122;integrated security=True;"));
Server server = new Server(conn);
JobCollection jobs = server.JobServer.Jobs;
var stepInformationsDetailsList = new List<StepInformationsDetails>();
foreach (Job job in jobs)
{
foreach (JobStep jobstep in job.JobSteps)
{
stepInformationsDetailsList.Add(new StepInformationsDetails() {
ServerName = job.Parent.MsxServerName,
ReportName = job.Name,
StepName = jobstep.Name,
Command = jobstep.Command,
Schedual = jobstep.DatabaseName,
StepID = jobstep.ID
});
}
}
dataGridView1.DataSource = stepInformationsDetailsList;
That data will all be in your Command variable. When you override/add anything on the job step tabs, the net result is that the command line passed to dtexec has those values. The UI is simply slicing arguments out of the command column in the msdb.dbo.sysjobsteps table to link them to various tabs.
On your localhost, this query ought to return back the full command line.
SELECT
JS.command
FROM
dbo.sysjobs AS SJ
INNER JOIN dbo.sysjobsteps AS JS
ON JS.job_id = SJ.job_id
WHERE
sj.name = 'Concessions made by Simba Auto-Report';
Since you are not overriding the value of the Connection Manager 'Simba Replica...', it is not going to show up in the output of the command. If it was, you'd have a string like /SQL "\"\MyFolder\MyPackage\"" /SERVER "\"localhost\sql2008r2\"" /CONNECTION SYSDB;"\"Data Source=SQLDEV01\INT;Initial Catalog=SYSDB;Provider=SQLNCLI10.1;Integrated Security=SSPI;Auto Translate=False;\"" /CHECKPOINTING OFF /REPORTING E The /CONNECTION section would correlate to your 'Simba Replica...' value.
I suspect, but do not know, that the UI is examining the SSIS package via the API Microsoft.SqlServer.Dts.Runtime and identifying all the Connection Manager, via Connections property to build out that dialog.

InstalledInstances doesn't work

I have a project with a database and I have to create a setup file to run another computer. I try to setup but firstly, I need to know is there any SQL Server already installed on that computer. I searched some code about it and I found:
RegistryKey rk = Registry.LocalMachine.OpenSubKey("\\SOFTWARE\\Microsoft\\Microsoft SQL Server");
String[] instances = (String[])rk.GetValue("InstalledInstances");
but everytime instances equal null everytime. But when I try to look myself on computer I find by hand. What's the wrong this code?
RegistryKey rk = Registry.LocalMachine.OpenSubKey("\\SOFTWARE\\Microsoft\\Microsoft SQL Server");
String[] instances = (String[])rk.GetValue("InstalledInstances");
if (instances.Length > 0)
{
foreach (String element in instances)
{
if (element == "MSSQLSERVER")
{
DialogResult res = MessageBox.Show("are u sure to setup this file?", "UYARI", MessageBoxButtons.YesNo);
if (res == DialogResult.Yes)
{
string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\SQLEXPR.EXE";
Process p = new Process();
p.StartInfo.FileName = path;
p.StartInfo.Arguments = "/qb INSTANCENAME=\"SQLEXPRESS\" INSTALLSQLDIR=\"C:\\Program Files\\Microsoft SQL Server\" INSTALLSQLSHAREDDIR=\"C:\\Program Files\\Microsoft SQL Server\" INSTALLSQLDATADIR=\"C:\\Program Files\\Microsoft SQL Server\" ADDLOCAL=\"All\" SQLAUTOSTART=1 SQLBROWSERAUTOSTART=0 SQLBROWSERACCOUNT=\"NT AUTHORITY\\SYSTEM\" SQLACCOUNT=\"NT AUTHORITY\\SYSTEM\" SECURITYMODE=SQL SAPWD=\"\" SQLCOLLATION=\"SQL_Latin1_General_Cp1_CS_AS\" DISABLENETWORKPROTOCOLS=0 ERRORREPORTING=1 ENABLERANU=0";
p.StartInfo.CreateNoWindow = true;
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
p.Start();
p.WaitForExit();
CreateDB();
}
else
{
this.Close();
}
}
}
}
You need to drop the initial \:
Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Microsoft SQL Server");
But when run on my 64-bit machine from 32-bit .Net executable, it doesn't actually report the installed instances. That's because they are only in the 64-bit view of registry. To get there from 32-bit process under .Net 4, you can use this code:
var localMachine = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
var rk = localMachine.OpenSubKey("SOFTWARE\\Microsoft\\Microsoft SQL Server");
var instances = (String[])rk.GetValue("InstalledInstances");
I'm not sure if this is the only problem but I notice you are escaping the " and not the \ so you want an # prefix on the string and double " instead of \" like so:
p.StartInfo.Arguments = #"/qb INSTANCENAME=""SQ... rest of string ... ";
Using the # formatted strings is easier IMHO or you could go back and replace every instance of \ in the target path with \\
From MSDN it seems you have to test for 32 vs 64
try
{
// That works fine in Win32 but not in Win64
return Registry.LocalMachine.OpenSubKey("Software\\XXX\\YYY").GetValue("Path").ToString();
}
catch (Exception)
{
// That works fine in Win64 but not in Win32
return Registry.LocalMachine.OpenSubKey("\\Software\\XXX\\YYY").GetValue("Path").ToString();
}
you need to check what key is taken, because you might not pointing to the correct key, to know what actual key that you have do this:
string keyValue = registryKey.ToString();
if you found a different key that what you have been using which is: SOFTWARE\\Microsoft\\Microsoft SQL Server, then you should change the projects build, since the registries can be for 32 or 64, so specify which CPU, not "any CPU"

Categories

Resources