Backup localDB database in ClickOnce - c#

I've created a WPF 4.5 .NET application it with a database backup feature. The functions and the backup works fine when debugging but when I publish it in ClickOnce and install it in target machine everything works except the backup won't work because ClickOnce obfuscate the app folder location so it becomes too long for the backup statement to work! Is there a way to make the backup statement shorter? here's my code and the error I get:
code:
SaveFileDialog sfd = new SaveFileDialog();
string stringCon = #"Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\whdb.mdf;Integrated Security=True";
string dbPath = Application.StartupPath + #"\whdb.mdf";
if (sfd.ShowDialog() == DialogResult.OK)
{
using (SqlConnection conn = new SqlConnection(stringCon))
{
string backupStmt = string.Format(#"backup database #whdb to disk='{0}' WITH INIT ", sfd.FileName);
using (SqlCommand sqlComm = new SqlCommand(backupStmt, conn))
{
sqlComm.Parameters.AddWithValue("#whdb", dbPath);
conn.Open();
sqlComm.ExecuteNonQuery();
conn.Close();
}
}
)
************** Exception Text **************
System.Data.SqlClient.SqlException (0x80131904): Invalid database name 'C:\Users\Abubaker\AppData\Local\Apps\2.0\52WR4JTO.12O\D6M4D7OQ.Z3D\sa3a..tion_fef19ab42c2b8f22_0001.0000_9fc10c82bbf23ed2\whdb.mdf' specified for backup or restore operation.
BACKUP DATABASE is terminating abnormally.

The whdb.mdf database file is create by another existing application? And your WPF application is only for Backup the existing whdb.mdf database?
I also struggled for days for this kind of situation. I tried |Data Directory| and Application.StartupPath and some other approaches as you've found as well.
However, I finally chose this way and successfully launched(published) my service.
According to my experience, |Data Directory| indicates different places depending on circumstances, in other word, it's not always same..
And I could read (SQL Select command) database with |Data Directory| setting in connectionString but couldn't insert or update the database. You can find some people are having this difficulties by searching on interent. I think when we set |Data Directory| in connectionString, the database plays a role as read-only data file like the nuance of |Data Directory|.
Instead the |Data Directory|, I chose more obvious path which indicates always same place(directory).
#"Data Source=(LocalDB)\v11.0;AttachDbFilename=" + Environment.GetEnvironmentVariable("APPDATA") + #"\whdb.mdf;Integrated Security=True";
Above Environmental variable indicates always C:\Users\Abubaker\AppData\Roaming directory.
For this scenario, you're needed to create the whdb.mdf database file with above path first.
And further, you may create your own additional directory like mybackup with the connectionString as,
#"Data Source=(LocalDB)\v11.0;AttachDbFilename=" + Environment.GetEnvironmentVariable("APPDATA") + #"\mybackup" + #"\whdb.mdf;Integrated Security=True";
I couldn't find the official document from Microsoft how the |Data Directory| works but failed. Understanding |Data Directory| would be your key, otherwise, there's alternative way like my case.
My case is also WPF, ClickOnce, SQL Database (it was localDB but I changed to normal SQL Database because of remote networking)

Solved the problem by adding Initial catalog=whdb in the connection string and then replace the full path Application.StartupPath + #"\whdb.mdf" with just the database name "whdb"!

Related

Unable to load database from local server location in C# Connection String (windows application)

I'm trying to do application to access the database from local file server, but the connection string does not recognize the server location. This is a windows form application, using sqlite. Kindly help me on this one.
File server location will be like this:
\\fileserver\Testdb\maindb.db
Code used:
string server_database_path = #"\\fileserver\Testdb\maindb.db";
string connection_data = "Data Source=" + server_database_path ;
using (var conn = new SQLiteConnection(connection_data))
{
conn.Open();
SQLiteCommand insert_Rec = new SQLiteCommand(query_text, conn);
insert_Rec.ExecuteNonQuery();
conn.Close();
}
Error:
Unable to open database file
I may be wrong but I dont think that directly specifying the .db is correct. When using a normal SQL Server I would specify the instance (or just the server hosting it if it was the default instance).
So, your connection string should look something like
string connectionString = "Data Source=192.168.0.1; User ID=administrator; Password=YOURPASSWORD"
or if you are connecting the machine you are on it should be
string connectionString = "Data Source=127.0.0.1; User ID=administrator; Password=YOURPASSWORD"
You could substitute the 127.0.0.1 for \\localhost
I was confused in doing this, but by changing the slash "\" to "/" it really worked.
When i changed the slash in the path string it started to work fine and everything goes well.
Example: #"//fileserver/Testdb/maindb.db"

How to save DataSet after adding data?

Yes, I know that this questions has been asked at least 5-10 times in here, but I can't for the life of me get any of the methods to save the data.
The idea is to create a new row in table Companies in column Name (there is only one column) with value "asdf"`.
I've tried combinations of the following:
DatabaseDataSetTableAdapters.CompaniesTableAdapter adapter = new DatabaseDataSetTableAdapters.CompaniesTableAdapter();
DatabaseDataSet ds = new DatabaseDataSet();
adapter.Insert("asdf");
adapter.Fill(ds.Companies);
adapter.Update(ds.Companies);
ds.AcceptChanges();
ds.Companies.AddCompaniesRow("asdf");
ds.Companies.AcceptChanges();
ds.Companies.AddCompaniesRow("asdf");
ds.Companies.Rows[0]["Name"] = "asdf";
adapter.Update(ds.Companies);
I'm using C# WPF .NET 4.5.1
It does add the data, but it doesn't save it when I exit the program - I know that it adds data, because if I call this method twice it crashes, because the value is no longer unique.
Here is the DatabaseDataSetTableAdapters:
http://pastebin.com/gNsaRFD5
This did not work either:
SqlConnection myConnection = new SqlConnection(global::AliBabaMailer.Properties.Settings.Default.DatabaseConnectionString);
myConnection.Open();
SqlCommand myCommand = new SqlCommand("INSERT INTO Companies (Name) " +
"Values ('string')", myConnection);
myCommand.ExecuteNonQuery();
myConnection.Close();
Ok so your problem is the Connection String:
Properties.Settings.Default.DatabaseConnectionString
This connection string is of the form:
“Data Source=ServerName;AttachDbFilename=|DataDirectory|\DataBaseName;Integrated Security=True”
The |DataDirectory| is usually here:
C:\Users\UserName\AppData
When you save the data it is being saved to a database file at `|DataDirectory| location but when you try to view the data using Server Explorer you are trying to view from a database file which is in your project's folder, that is why If you try to save and then view the data on run time it will work fine because then you will be querying the same database you are storing your data into.
|DataDirectory|:
|DataDirectory| (enclosed in pipe symbols) is a substitution string that indicates the path to the database. It eliminates the need to hard-code the full path which leads to several problems as the full path to the database could be serialized in different places. |DataDirectory| also makes it easy to share a project and also to deploy an application.
For example, instead of having the following connection string:
"Data Source= c:\program files\MyApp\Mydb.sdf"
Using DataDirectory, you can have the following connection string:
“Data Source = |DataDirectory|\Mydb.sdf”
To set the DataDirectory property, call the AppDomain.SetData method. If you do not set the DataDirectory property, the following default rules will be applied to access the database folder:
For applications that are put in a folder on the user's computer, the database folder uses the application folder.
For applications that are running under ClickOnce, the database folder uses the specific data folder that is created.
Link
Coding Advice:
Try to dispose your Command and Connection Objects like this:
using(SqlConnection myConnection = new SqlConnection(global::AliBabaMailer.Properties.Settings.Default.DatabaseConnectionString))
using(SqlCommand myCommand = new SqlCommand("INSERT INTO Companies (Name) " + "Values ('string')", myConnection))
{
myConnection.Open();
myCommand.ExecuteNonQuery();
myConnection.Close();
}

how to set a path to the local directory in c# for .mdf database in Service.cs file

Do you know how to set a path to the local directory in c# when trying to set a path for a datbase in the service.cs file? (I am developing in VS2010)
I have developed a winforms program that uses a .mdf (SQL Server) database. The program communicates to the database through a SQL Server connection string.
I have hard coded the path of the db at the mo but would like to know how to point to the current directory.
I have seen online
AttachDbFilename =|DataDirectory|\Database.mdf
But it doesn't seem to work for me as the connection will not open.
Also I have tried using Environment.CurrentDirectory however that with CurrentDirectory is weirdly not in the namespace.
If the file is in the same assembly folder you can use this
string folder = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.ConnectionStrings.ConnectionStrings["myCS"].ConnectionString = config.ConnectionStrings.ConnectionStrings["myCS"].ConnectionString.Replace("#folder#",folder);
config.Save(ConfigurationSaveMode.Full, true);
Go to solution Explorer >> right click the project>> click properties>> go to setting tab>>Make name: MyConnectionString Type:(connection string) Scoper: Application
and select the DB(Db should be kept in your |DataDirectory| along with your dblog)>> select that DB. >> save it.
Then use this code for connection
SqlCeConnection cnn = new SqlCeConnection(Properties.Settings.Default.MyConnectionString);
You have to give the namespace: using System.Data.SqlServerCe;
hope this will solve.
Accept if this works and close the question
there is a way to get the .mdf and .ldf of a databese, through the code that have worked for me, to do that, open a connection to the database using the connection string, prepare SQL command, with the query
select physical_name from sys.database_files where type = 0
then execute the command, and by the way, type = 0, is for mdf, and type = 1 is for ldf, you can also use this query directly in the SSMS
this is the sample code, keep in mind that you need to get the connection string
string _mdfCommand = "select physical_name from sys.database_files where type = 0";
string _ldfCommand = "select physical_name from sys.database_files where type = 1";
SqlCommand GetSQLData = new SqlCommand();
SqlConnection connection = new SqlConnection(connectionString);
connection.Open();
GetSQLData.CommandText = _mdfCommand;
GetSQLData.Connection = connection;
string mdf_Path= (string)GetSQLData.ExecuteScalar();
GetSQLData.CommandText = _ldfCommand;
GetSQLData.Connection = connection;
string ldf_Path= (string)GetSQLData.ExecuteScalar();
connection.Close();

Why do I get "Database already exists" when I'm using "AttachDbFileName" when I move the solution to another directory?

I have an application JigSaw that uses a database TopScores.mdf which it is not included in the project. What I want to do is make the application find the database in application's folder. So for example if I move the .exe file and the database file from debug folder to desktop the application should use the database from desktop and not search for it in debug folder.
If I let them in debug folder there is no problem and the connection to database is established, but when I put them on desktop I get this :
Unhandled exception has occurred in your application. If you click Continue, the application will ignore this error and attempt to continue. Database 'D:\Programing\Projects Visual Studio 2010\JigSaw\JigSaw\bin\Debug\TopScores.mdf' already exists. Choose a different database name. Cannot attach the file 'C:\Users\Addy\Desktop\Jigsaw\TopScores.mdf' as database TopScores.mdf
My connection string is :
string appPath = Path.GetDirectoryName(Application.ExecutablePath);
string connString = #"server =.\sqlexpress; Database=TopScores.mdf; trusted_connection=TRUE; AttachDbFileName= "+#appPath+#"\TopScores.mdf";
conn = new SqlConnection(connString);
Sorry for my bad english :(
This is happening because you don't leverage the User Instance=true; when you connect to it. You literally told SQL Server to attach the database to the running SQL instance from the directory you first loaded it from.
Detach the database by hand from the running SQL instance, change your connection string to use User Instance=true;, run it from the Debug folder, and then run it from the Desktop, and you'll see success.
change setting in your connection string from "Database=TopScores.mdf" to something different, say: "Database=TopScores_brand_new_connection" do not create/delete/rename files in any file/database server. do it in the connection string only. Do not add dots, extensions etc.
just rename ur .mdf file ... eg. from MNGMT.mdf to M_1(something you want). change your contact string...hope so it will help u.. in my case it is executing correctly on other pc as well as in my pc.. just copy your .mdf file into you project ..
string dbPath = Path.GetDirectoryName(Application.ExecutablePath) + "\\M_1.mdf";
string myServer = Environment.MachineName;
DataTable servers = SqlDataSourceEnumerator.Instance.GetDataSources();
for (int i = 0; i < servers.Rows.Count; i++)
{
if (myServer == servers.Rows[i]["ServerName"].ToString()) ///// used to get the servers in the local machine////
{
if ((servers.Rows[i]["InstanceName"] as string) != null)
servername = (servers.Rows[i]["ServerName"] + "\\" + servers.Rows[i]["InstanceName"]);
else
servername = ""+servers.Rows[i]["ServerName"];
}
}
connetionString = "Data Source=" + servername + ";AttachDbFilename=" + dbPath + ";Integrated Security=True;Pooling=False;User Instance=True";

Microsoft ACE OLEDB connection creating empty Excel when there are 166,110 rows

I am programming in C# and using an oledbconnection. This is the standard connection string e.g.
using (OleDbConnection conn = new OleDbConnection(
"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" +
saveFilenameAndLocation +
";Extended Properties='Excel 12.0 Xml;HDR=Yes'"
))
This works successfully and creates my Excel spreadsheet full of the correct data, when the number of rows isn't excessive. However, whenever the number of rows in the spreadsheet increases to a large size (e.g. currently it is failing on 166,110 rows), it produces an empty spreadsheet with the worksheet tab name set to A266FF2A662E84b639DA.
It is not possible to rewrite this so that it doesn't use an OLEDB connection, any ideas why it doesn't work when the row size increases?
I am not sure about your application environment, but I have seen this when generating Excel files from an ASP.NET app.
Once the amount of data exceeds a certain size (~1 MB in my experience), the provider will attempt to create a temp file while generating the output. I have come across this issue using the 32-bit provider on 64-bit systems. If you are running under a service account with this configuration then the location where these files are created is
C:\Windows\SysWOW64\config\systemprofile\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.MSO
This location, however, is only accessible to administrators and SYSTEM by default, and if the provider is running under a non-privileged account and is unable to create the temp file it will fail silently and just return its default "empty file" with the A266FF2A662E84b639DA worksheet.
What you need to do is grant the account of the application that runs under (for example Network Service or IIS AppPool\) read/execute/list contents permissions along the path "C:\Windows\SysWOW64\config\systemprofile\AppData\Local\Microsoft\Windows\Temporary Internet Files" and then full access to the Content.MSO folder itself.
If the provider matches the bitness of your system then I suspect you need to perform the process above for C:\Windows\System32\config\systemprofile\AppData\Local\Microsoft\Windows\Temporary Internet Files\Content.MSO instead, although I have never tested this.
I want to extend my thanks to sysinternals for providing procmon that helped me troubleshoot this issue.
One of the employees at my company ran across this problem today. The solution was simple: She had only 20MB free space left on C: - If you free up enough space on your system drive, it should solve the problem.
Windows Server 2012R2
Check also if folder INetCache exists and this folder has full perimissions C:\Windows\SysWOW64\config\systemprofile\AppData\Local\Microsoft\Windows\INetCache
After 10 hours I found the solution.
Every 1000 rows we have to close and reopen the connection.
Sample is here.
string createTable = "Create Table [Sheet_X] (field1 char(255), field2 char(255),field3 char(255));";
OleDbCommand cmd = new OleDbCommand(createTable, conn);
conn.Open();
cmd.ExecuteNonQuery();
var counter = 0;
foreach (var item in items)
{
if (conn.State == ConnectionState.Closed)
conn.Open();
string insertdata = "insert into [Sheet_X] (field1,field2,field3) values('value1','value2','value3');";
counter++;
if (counter >= 1000)
{
counter = 0;
conn.Close();
}
}
If it still don't work after tried all above solutions, try this one, it worked for me:
In the "Advanced settings" of your IIS Application Pool, Change the value of "Load User Profile" from "False" to "True".

Categories

Resources