I am doing a SETUP project for a C# winforms, sqlite application.
Connection string seems to a bit of a problem. The user will put the Database he wants to work with at a location(which v will tell him). In this example it is "C:\\Program Files(x86)\\DefaultCompany\\RSetup"; The user can work his own copy of the DB.
So I am setting the data directory to this path in the Program.cs Main
This is the only way I can think of. If there is a better way thats grt!!.
App.config
<add name="ConnString" connectionString="|DataDirectory|\MySQlite.db;Compress=True;Version=3"
providerName="System.Data.Sqlite" />
Program.cs
Setting the datadirectory to the path of the executable. Currently hard coded the path of the executable
static void Main()
{
AppDomain.CurrentDomain.SetData("DataDirectory","C:\\Program Files(x86)\\DefaultCompany\\RSetup");
This doesn't seem to be working. It doesn't give any error except the data is not blank. Doesn't seem to be working in both set up and the regular project
Thank you
JC
You could ask the user where the database is located, store that path somewhere (such as User Settings) and then you can retrieve it at any time. This would give the user more flexibility of where to put it and multiple users on the same machine could have their own database if desired.
Here is some pseudocode...
string dbLocation = Properties.Settings.Default.DatabaseLocation;
if (string.IsNullOrWhiteSpace(dbLocation)
{
dbLocation = AskUserForLocation();
Properties.Settings.Default.DatabaseLocation = dbLocation;
Properties.Settings.Default.Save();
}
AppDomain.CurrentDomain.SetData("DataDirectory",dbLocation);
Using this approach you could also add a menu option to allow the user to change the location if desired.
It also gives you the ability to retrieve the value anywhere, including where you create a connection, you can append the path to the location between where you read the connection string and you create a new connection.
SQLiteConnection myConnection = new SQLiteConnection;();
myConnection.ConnectionString = Path.Combine(Properties.Settings.Default.DatabaseLocation, myConnectionString);
myConnection.Open();
Related
I'm working on an app that has a live network database and a contingency local database, and it detects whether the live network db is accessible, and, if not, it times out after three seconds, changing the connectionstring to the local contingency database.
Following tips here on SO, I managed to alter the connectionstring on app.config during run time and reload the settings.
This is the method the app calls when a change on the connection string is needed:
public static void ChangeConnectionString(string connectionstring)
{
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var connectionStringsSection = (ConnectionStringsSection)config.GetSection("connectionStrings");
connectionStringsSection.ConnectionStrings[0].ConnectionString = connectionstring;
var connectionStrings = config.ConnectionStrings;
foreach (ConnectionStringSettings connectionString in connectionStrings.ConnectionStrings)
{
connectionString.ConnectionString = connectionstring;
}
config.Save();
ConfigurationManager.RefreshSection("connectionStrings");
PDV_WPF.Properties.Settings.Default.Save();
PDV_WPF.Properties.Settings.Default.Reload();
//Ensures the configuration is saved and reloaded.
FbConnection.ClearAllPools();
//Closes all currently open connections which might be using the old connection string.
Debug.WriteLine("==========Ran ChangeConnectionString");
Debug.WriteLine("==========FDBConnString is:");
Debug.WriteLine("==========" + PDV_WPF.Properties.Settings.Default.FDBConnString);
After I disconnect my computer form the network, whenever I check the current FDBConnString, it correctly points to the local contingency database. However, on the very next line, when it tries to run a query, I get the following exception:
Inner Exception 1:
IscException: Unable to complete network request to host "dbserver".
Inner Exception 2:
SocketException: Este host não é conhecido //(This host is unknown)
Full exception details: https://pastebin.com/3syLvsQf
It seems that, even after I successfully change the connection string, and successfully reload the application config file, it still tries to open a connection using the old connection string. Even if I call Debug to print the current Properties.Settings.Default.FDBConnString right on the line above the call for FbConnection.Open(), it shows the new string rather than the incorrect, old one.
Any insights on what might be going on?
I found what was the issue.
I am instancing a inherited table adapter from the generated xsd file. When I declare a table adapter on my class it also inherits the connection string stored on app.config at the time of declaration. So it doesn't matter if I change app.config, as the declared table adapter is already stuck with the previous connection string.
So, the solution was, rather than changing the connection string stored on app.config, I just had to change the connection string on the declared table adapter:
tB_STOCKTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.ContingencyDB;
tB_STK_PRODUCTTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.ContingencyDB;
or
tB_STOCKTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.NetworkDB;
tB_STK_PRODUCTTableAdapter1.Connection.ConnectionString = Properties.Settings.Default.NetworkDB;
Both ContingencyDB and NetworkDB are strings stored on app.config as a user-scoped string, which can be changed via a given "Settings" window presented to the user.
I want the user to be able to edit the connection string, I've set up a file browser dialogue where they can only select .accdb files, and I'm trying to have the save button overwrite the current connection string with the file path from the text box. I've had multiple errors at different times and I've ended up with a setup that seems tantalisingly close to working but I have a NullReferenceException error which says "Object reference is not set to an instance of an object". Hopefully this is a newbie mistake.
var configuration = ConfigurationManager.OpenExeConfiguration(#"\\Mac\Home\Documents\Visual Studio 2015\Projects\tiddlywinks\tiddlywinks\App.config");
var section = (ConnectionStringsSection)configuration.GetSection("connectionStrings");
section.ConnectionStrings["tiddlywinksDatabaseConnectionString1"].ConnectionString = #"Provider = Microsoft.ACE.OLEDB.12.0; Data Source ='" + filePathTextBox.Text + "'; Persist Security Info=False;";
configuration.Save();
This is the code that I have atm. Can anyone help?
Also, is there a way to achieve the same without having to tell the program where App.config is, surely Visual Studios knows where it's own config files are?
You can do that this way:
You go to your solution properties
Properties => Settings => Add new Settings
(Make sure Scope is "user")
and add a new sitting for your connection string, let's call it : ConnectionString
like mentioned in this post:
Applications sittings
then all you have to do is
Properties.Settings.Default.ConnectionString = TextBoxConnectionString.Text
Properties.Settings.Default.Save();
Give it a try, Hope it helps !
user cannot change application setting at run time.
It can be modified only at design time.
Use User settings for this.
How to : Using Application Settings and User Settings
Regards
See DGibbs answer below.
I can't have the config file saved with the EXE, as this is present on each user's desktop, so it seems I am unable to store the password in the config file and will have to come up with some other solution.
I have an app that needs to run a CMD command as an administrator. To achieve this, I stored the password in a connection string in app.config:
<connectionStrings>
<add name="mypw" connectionString="PASSWORD" />
</connectionStrings>
I am then able to call this in my Cmd class as a SecureString:
private static SecureString pw()
{
string connectionString = ConfigurationManager.ConnectionStrings["mypw"].ConnectionString;
SecureString ss = new SecureString();
foreach (char c in connectionString)
{
ss.AppendChar(c);
}
return ss;
}
When I run the app from VS on my machine with debugging (F5), it works fine and the password is retrieved. However, when running it in a development environment I see the exception Object Reference not set to an instance of an object, and from my own debugging I can see that this is happening at this line:
string connectionString = ConfigurationManager.ConnectionStrings["mypw"].ConnectionString;
Can anyone please explain why the app is able to retrieve the connection string on my machine but not when deployed elsewhere? Does the app.config file change when publishing the app?
Few things, don't use <connectionStrings>, this is typically used to store credentials for a db connection, it doesn't make sense here. Try using AppSettings within the App.config file e.g
<appSettings>
<add key="mypw" value="password" />
</appSettings>
You can retrieve the value like this:
string pw = ConfigurationSettings.AppSettings["mypw"];
Finally, make sure you have the config file deployed, it should be [ApplicationName].exe.config and not App.Config. If it doesn't appear, check the Copy to output directory setting, make sure it's set to Copy Always.
I have built my application in c# and have an sql compact DB to go along with it. What do I need to change the location to in order for it to point to the same directory as the application.
For example:
Right now my DB is in C\Windows blah blah...
And in my code I make the source point to that...when I build the project my app is in bin\release along with my DB file, but in my code the source is not pointed to this DB file..does anyone know what I need to insert to point it to the correct DB file?
Thanks..
Is it always going to be in the same directory as the application executable? If so, perhaps you can just set the connection string using the path of the current assembly (assuming everything is in the same place):
string curPath = String.Format("{0}\\{1}", System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase), "MyDatabase.sdf");
SqlCeConnection conn = new SqlCeConnection(String.Format("Data Source = {0}; Password ={1}", curPath , ":PASSWORD:");
Is it possible to modify the connectionstrings defined in the app.config/web.config at runtime? I want to use different configfiles depending on the machine the app/site is run on (only for debugging purposes, of course. We'll use the regular config files when deployed).
I can write AppSettings, but not ConnectionStrings (AFAIK). Or can I?
Yes it's possible, but AFAIK only via Reflection. The following code should do what you need (read below for usage):
public static string SetConnectionString(Type assemblyMember,
Type settingsClass,
string newConnectionString,
string connectionStringKey)
{
Type typSettings = Type.GetType(Assembly.CreateQualifiedName(assemblyMember.Assembly.FullName, settingsClass.FullName));
if (typSettings == null)
{
return null;
}
PropertyInfo prpDefault = typSettings.GetProperty("Default", BindingFlags.Static | BindingFlags.Public);
if (prpDefault == null)
{
return null;
}
object objSettings = prpDefault.GetValue(null, null);
if (objSettings == null)
{
return null;
}
// the default property, this[], is actually named Item
PropertyInfo prpItem = objSettings.GetType().GetProperty("Item", BindingFlags.Instance | BindingFlags.Public);
if (prpItem == null)
{
return null;
}
object[] indexerName = { connectionStringKey };
string oldConnectionString = (string)prpItem.GetValue(objSettings, indexerName);
prpItem.SetValue(objSettings, newConnectionString, indexerName);
return oldConnectionString;
}
assemblyMember is the calling type
settingsClass is the type of your settings class
newConnectionString is the full string to set
connectionStringKey is the name of the connection string that you defined in your app's settings
You should call this method as soon as possible after your app has started, preferably in the Main() method.
I tried this once in my project for debugging purpose but could not do it, the problem (I guess, correct me if I am wrong) is on app start up the app.config gets loaded into the memory, any changes to app.config while the app is running do not get reflected.
To overcome this here's what I did, define all the connectionstrings in the app.config and then call the ones that you want when your program is running like this.
for example lets assume you defined your connectionstrings in the app.config as follows.
<connectionStrings>
<add name="YourNameSpace.Properties.Settings.ConnectionString_1"
connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=|DataDirectory|\file.mdb"
providerName="System.Data.OleDb"/>
<add name="YourNameSpace.Properties.Settings.ConnectionString_2"
connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data
Source=|DataDirectory|\file.mdb"
providerName="System.Data.OleDb"/>
</connectionStrings>
define as many as you want (you are debugging right :-) )
then to call those connection settings in your code do something like this:
YourNameSpace.Properties.Settings foo = new YourNameSapce.Properties.Settings();
foo.ConnectionString_1;
HTH
Best Regards
#nand
P.S: This reply is specific to C#.
You can't really edit the config file of the running process.
One option (with pros and cons) is to use config data in the machine.config or the master web.config (for "site", you use the "location" nodes) - not an option to rush into, though.
A better way to handle this is to swap the config file as part of your build/deploy process, ideally automated. That way, everything is self-contained, and you can "robocopy" to a vanilla server and have it work.
Re your "per developer" point; I found that the easiest way to do this was to standardise the config, and tweak the machines. For example, we run a local web-server on a VM; rather than code against each machine, we standardise on "localserver" (to mirror "localhost"), and add a local DNS record to each machine that the developer can control. Note that this requires fixed IP addresses (or maybe a DHCP reservation) to prevent it changing over time!
Ditto databases; local servers can use "."; remote servers can be aliased on the machine, so "devserver" points to whatever the user wants.
Just a thought...
You could run xmlpoke in a NAnt script when installing the website.
E.g.
Deploy the NAnt with the website.
Create a go.bat that calls NAnt which installs the site and does xmlpoke to modify the web.config with settings based on the server name or some other parameter.