How to deploy a C# WPF app with a sqlite database? - c#

I've created a C# WPF application which interacts a SQLite database. I want to create installation file so as to be able to install the app on another computer. Does anyone know how to deploy C# WPF app with SQLite database, I've created a setup file by using ClickOnce, but when I run the app and do something with the app which requires fetching data from database, the shuts down.

I don't think it's all about making the installation file. I think, the application crashes because the software can't find the database. If you develop your software in such a way that, it creates the database (if it doesn't exit) on startup, the way you create the installation file won't be a problem. Here is what I mean:
//use an environment generated file path.
public string _dataBasePath = $#"{ System.Environment.GetFolderPath(System.Environment.SpecialFolder.ApplicationData)}\databaseName.db";
Using an object relational mapper like NHibernate. You can override OnStartUp and create your database:
// In the App.xaml.cs class
private override void OnStartup(StartupEventArgs e) {
base.OnStartup(e);
BuildSchemaAction(config);
}
private void BuildSchemaAction(Configuration config) {
new SchemaExport(config).Create(false, !File.Exists(_dataBasePath));
}
protected Configuration config = new Configuration();
The database file (since it is SQLite) will not exist, so it will be created. Subsequently, it will not be created.
The _dataBasePath field will be the path in the connection string, in order to access the database in the path it was created.
x.ConnectionString = $"Data Source={_dataBasePath};version=3";

Related

Publishing a shared appsettings file with .net core

I have a .net core solution that contains a database project (class library) and a console application. The database project contains EF Migrations and to do Add-Migration, most methods use a hard-coded connection string in one place or the other.
To avoid hard-coding (and/or duplication) I have created a shared appsettings.json file in the solution root and I use it in my Main method and the class library
In the console application
static void Main(string[] args)
{
var settingPath = Path.GetFullPath(Path.Combine(#"../appsettings.json"));
var builder = new ConfigurationBuilder()
.AddJsonFile(settingPath, false);
var configuration = builder.Build();
var services = new ServiceCollection()
.AddDbContext<MyContext>(options => options.UseSqlServer(configuration["ConnectionStrings:MyDatabase"]))
.BuildServiceProvider();
}
And in the class library to use migrations
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyContext>
{
public MyContext CreateDbContext(string[] args)
{
var settingPath = Path.GetFullPath(Path.Combine(#"../appsettings.json"));
var builder = new ConfigurationBuilder()
.AddJsonFile(settingPath, false);
var configuration = builder.Build();
var optionsBuilder = new DbContextOptionsBuilder<MyContext>()
.UseSqlServer(configuration["ConnectionStrings:MyDatabase"]);
return new MyContext(optionsBuilder.Options);
}
}
This is working well for development purposes when I use dotnet run but when I publish the console application, it doesn't include the appsettings file. Other than running a powershell script as part of dotnet publish, is there any other cleaner way of including this file when the project is published?
IDesignTimeDbContextFactory is exactly for the purpose its name describes. You shouldn't be running migrations against your production database in the first place, and if you do, you should be generating specific migrations for production into your app (instead of the class library) and using your app for the migrations. See the docs on using a separate project for migrations. That, then, negates the need to share your appsettings.json. Just leave the connection string hard-coded in your factory, since it's only for development anyways.
Now, you might have an issue I suppose in a team environment. However, even if you're using something like SQLite, you can use project-relative paths that won't be developer-specific, and with LocalDB, you can use a normal SQL Server connection string to the MSSQLLocalDB instance, which will be same for every developer using Visual Studio. Regardless, even if you do need to specify the connection specifically by developer, at that point it would make more sense to use user secrets, anyways, since you wouldn't want that info be committed to source control. Otherwise, each developer would end up clobbering the other's copy of appsettings.json, and you'd have a mess on your hands.
Long and short, just hard-code the connection string in your factory, or if you can't or won't, use user secrets for the connection string. In either case, you do not need to share appsettings.json.
The way I've done this before is to specify the startup project when you run dotnet ef (with the -s switch - the options are at https://learn.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet#common-options)
It gets messy quickly, and it's probably easiest to write some wrapper scripts for the project that deal with this kind of thing.

Can i use clickOnce to deploy MS Access database?

i have developed an application in a .mdb access file with tables linked to sql server
i try toput the mdb file in folder shared to all user but simultaneus access break the file very often.
so iam trying to deploy the .mdb file to every client machine and keep it update. i have created a winform app that check mdb file version and copy it to a local folder and next opens the local copy
but even in this way i have problem if too many user uses the winform launcher appat same time
so iam thinking if there is a bettere and simpler way:
can i use clickonce to deploy directly the access file and create a silly webform to launch it?
i have created the webform but how can i add the mdb file to deploy process? i have to add it to resources? and in that case embedded or not?
and in that case how clickonce detect that the access is a modified one?
If I understand correctly, your .mdb file is the front end to a SQL Server back end. In that case, yes, each user should have their own copy of that FE. If you do a web search, there are many solutions for distributing an Access FE, without having to re-invent the wheel. A favorite is Tony's Auto FE Updater http://autofeupdater.com/.
Found the solution finally:
i add the db to Resources, setting build action to "Content", then my program.cs is this:
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
string nomeFile = #"\EW.accde";
string DestinationPath;
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
DestinationPath = System.IO.Path.GetDirectoryName(path) + #"\Resources";
Process.Start(DestinationPath + nomeFile);
}
in this way i simply copy the new db in project and then deply app with clickonce
once installed app simply launch the database file

C# Project - InstallShield , MySql error when run after installation

I have a project in C# which is created in Visual Studio 2013. I want to create an installer using Install Shield free version. I created an installer and trying to run it on other computer but, when I run it and trying to log into program, I have problems about mysql database. Error message is:
Unhandled exception has occured in you application. If you click Continue, the application will ignore this error and attempt to continue. If you click Quit, the application will close immediately.
Cannot connect.
If I click on details button, I have a serie of errors which refers on Mysql. Example:
System.Exception: Cannot connect ---> MySql.Data.MySqlClient.MySqlException: 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.GetPooledConnection()
at MySql.Data.MySqlClient.MySqlPool.TryToGetDriver()
at MySql.Data.MySqlClient.MySqlPool.GetConnection()
at MySql.Data.MySqlClient.MySqlConnection.Open()
at simulator.ConnConfig.getConnection()
simulator is the name of the project. ConnConfig is a class where is the connection and getConnection() is a function from ConnConfig which return connection. II tried to install on another computer .NET Framework 4.5.2, SQL Server, but also didn't worked.
In my project, I use localhost server where I have a database with 2 tables. My question is, is there any possibility to add that localhost database to installer and use it on another computer? And what redistributables requires this operation? Also, I have installed on computer .NET Framework 4.5, Sql Server 2012..but when I try do add them in InstallShield via Redistributables, but it keeps saying that Needs to be downloaded. Why?
UPDATE
I have this Class where I make the conenction. But I receive error: Additional information: Illegal characters in path. at that line:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SQLite;
namespace simulator
{
class ConnConfig
{
private static string conn = "Data Source=c:\aplicatie.db;Version=3;Password=myPassword;";
public static SQLiteConnection connect = null;
private ConnConfig()
{
}
public static SQLiteConnection getConnection()
{
SQLiteConnection connect = null;
try
{
connect = new SQLiteConnection(conn);
connect.Open();// here I receive the error
return connect;
}
catch (SQLiteException e)
{
throw new Exception("Cannot connect", e);
}
}
}
}
UPDATE 3
In that class I make the connection to database. In the other forms I just use tables and their data. For connection to program, I use a login form which uses this class to getConnection(). I created that database by adding an ADO.NET in simulator project. And with that, it comes those 2 tables that I already have in localhost server. So, Is ok if I have to create another empty database with new tables, but where to include that code or how to use it, because I don't get how that script works..where should I put it?
If your database is going to be installed on each client and your tables are not massive you might want to look at something lighter like SQLite which doesn't need any installation just the dlls and is very fast and efficient and only runs when your program does.
As for for the Needs to be Downloaded issue, it seems you have not setup your prerequisite correctly, you an correct this by following the steps in this article
Adding InstallShield Prerequisites, Merge Modules, and Objects to Basic MSI and InstallScript MSI Projects
You might want to look into determining if MySQL is the right solution for you.
SQLite vs MySQL vs PostgreSQL: A Comparison Of Relational Database Management Systems
And to see the limitations of SQLite SQLite
Because honestly seems like overkill to install MySQL on every system. If you had one server with MySQL on the network, okay. But on every system seems like a bad idea.
As far as connecting to an SQLite database here is a List of Connection Strings for SQLite
See this topic on how to create Databases and tables Create SQLite Database and table
My guess is your program doesn't bundle up the database alongside the setup upon deployment. This may be due to the fact that you didn't mark your database as a Data File in the Project Files. Try this, right click on your project name in Solution Explorer and select Properties from Menu. From the horizontal tabs click on the Publish Tab. Under Install Mode and Settings click the Application Files button. A dialog box appears with all Application files. Set your database Publish Status to Data File from the drop down on the corresponding cell. This way your database will be bundled together with the setup upon publishing. Hope this helps.
You can access SQLite via ODBC.

SQL Server Compact 4.0 database not detected after ClickOnce deploy

I have a WPF C# application and an SQL Server Compact 4.0 database. Initially I had my Data Source pointing to the location of the database like this:
public static SqlCeConnection sqlCeConnection = new SqlCeConnection(#"C:\VSP Road Maintenance Solution\VSPApp_Mono\VSPApp\VSPCompactDatabasse.sdf");
This worked great on my local machine but when I wanted to package the application (ClickOnce), it didn't work on the client's machine. After going through MSDN documentation on creating an ms sql server compact database and deploying it and other related similar issues such as http://social.msdn.microsoft.com/Forums/sqlserver/en-US/dc31ea59-5718-49b6-9f1f-7039da425296/where-is-datadirectory-?forum=sqlce and http://msdn.microsoft.com/en-us/library/37z40s1c(v=vs.110).aspx
I tried to access the AppDomain via C# like (in App.xaml.cs):
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Process p = Process.GetCurrentProcess(); // Pick desired process
p.PriorityClass = ProcessPriorityClass.RealTime; // Assign priority
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.SetData("DataDirectory", #"C:\VSP Road Maintenance Solution\VSPApp_Mono\VSPApp");
}
And now to create a connection to the database I just:
public static string dbFileName = "VspCompactDatabase.sdf";
SqlCeConnection sqlCeConnection = new SqlCeConnection(#"Data Source=|DataDirectory|\" +dbFileName);
This works on my local machine too, but when I create the ClickOnce package. The application does not seem to find the database. All the prerequisite software gets installed. Why is it that when the application is deployed on a different machine, the seems to be no connection with the database?

Updating Connection String in DLL from Winforms - Linq to SQL

I developed a class library that uses Linq To Sql to communicate with a database.
When I added this I used Server Explorer to add a database and all the tables I want to talk to.
It then built a .dbml file for me.
In the "Designer" file I can see:
public TPDataContext() :
base(global::TPAPI.Properties.Settings.Default.TruePotentialConnectionString, mappingSource)
{
OnCreated();
}
If I update the "Linq to SQL" it regenerates a new designer.cs file
It stored the connection string in Settings.settings with the scope of "Application".
All functions just fine.
But, I have then added a winfoms project that needs to change this setting. So I added the following code:
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.ConnectionStrings.ConnectionStrings["TPAPI.Properties.Settings.TruePotentialConnectionString"].ConnectionString = txtConnectionString.Text;
config.Save(ConfigurationSaveMode.Modified, true);
ConfigurationManager.RefreshSection("connectionStrings");
This updates the connection string in the dll but it only takes effect when the application is shutdown and restarted.
When I am upgrading clients it overwrites what the user had already entered when using it previously.
I cannot seem to work out the best way to:
Not overwrite previous user defined connection string when the app is upgraded.
Be able to save the new connection string and use it without having to stop/start the app.
Having had a read of other threads it appears that the dll shouldn't really have any "local" settings in it (?) and they should all be sent by the winforms app. But, I am unclear on how use Linq to Sql in the dll without it automatically looking/adding it's own connection string.
Can anyone help please?
Thanks
I have decided to rewrite all my DataContext calls to accept the connection string parameter.
I had to amend and test about 40 functions but now the connection string is stored in the winforms application as a user setting and overrides the default connection string generated by Linq to SQL.
So, now in my dll it now looks like
TPDataContext db = new TPDataContext(connStr);
HTH

Categories