Click here to Skip to main content
Email Password   helpLost your password?

Introduction

Connection strings in the My.Settings class are Application scoped. This causes a problem when deploying an application because the development machine only rarely will have the same connection string as the deployment target machine of your customer. Add to this the fact that strongly typed datasets' table adapters get their connection string from the My.Settings class, and this creates the need for some kind of workaround. The most common workaround I have seen involves setting the TableAdapter.Connection.ConnectionString property with the appropriate connection string before calling Fill(). However, this is non-intuitive for most people, and for very large projects, updating these commands can be problematic.

Here is a better way to persist changes to application scoped connection strings for strongly typed datasets. This will handle any number of connection string overrides you want, with only trivial editing. No need to modify or re-modify the settings.designer.vb file or set TableAdapter.Connection.ConnectionString settings on every table adapter in your project.

Background

How does it work? Well, all the settings, including the application scoped settings, are not kept in memory as read-only. So, the run-time value can be modified, and all future calls to the My.Settings item will get the modified value. What the application scoping does is refuse to persist them. So, this little addition to the MySettings class allows you to:

  1. Update the runtime value of the application scoped setting.
  2. Apply any saved user scoped override setting via the SettingsLoaded event before they are ever referenced by table adapters.
  3. Persist any modified application scoped setting to the user scoped override setting via the SettingsSaving event.

Using the Code

  1. Go to your project Properties, Settings, and make a user scoped string entry for each Application scoped connection string with the same base name plus an added suffix. For example, I use the suffix "UserOverride". If I have two application scoped connection settings called "ConnectionString1" and "ConnectionString2", then I create two user scoped strings (not (connection strings)) called "ConnectionString1UserOverride" and "ConnectionString2UserOverride".
  2. Create a new module called Settings.UserOverride.vb, and insert this code:
  3. Option Strict On
    Option Explicit On
    Namespace My
        Partial Friend NotInheritable Class MySettings
            Inherits Global.System.Configuration.ApplicationSettingsBase
    
            Private Shared userOverrides() As String = { _
                "ConnectionString1", _
                "ConnectionString2" _
            }
    
            Private Shared userOverrideSuffix As String = "UserOverride"
    
            Public Sub SetUserOverride(ByVal [property] As String, _
                                       ByVal value As String)
                Me([property]) = value
            End Sub
    
            Private Sub userOverride_SettingsLoaded(ByVal sender As Object, _
                    ByVal e As System.Configuration.SettingsLoadedEventArgs) _
                Handles Me.SettingsLoaded
                Dim userProperty As String
                For Each appProperty As String In userOverrides
                    userProperty = appProperty & userOverrideSuffix
                    If CType(Me(userProperty), String).Length > 0 Then
                        Me(appProperty) = Me(userProperty)
                    End If
                Next
            End Sub
    
            Private Sub userOverride_SettingsSaving(ByVal sender As Object, _
                    ByVal e As System.ComponentModel.CancelEventArgs) _
                Handles Me.SettingsSaving
                Dim userProperty As String
                For Each appProperty As String In userOverrides
                    userProperty = appProperty & userOverrideSuffix
                    Me(userProperty) = Me(appProperty)
                Next
            End Sub
        End Class
    End Namespace
  4. Edit the userOverrides() array to include the names of the Application scoped connection strings in your application for which you have created user overrides. If you used a different suffix for your overrides, then change the userOverrideSuffix value also.
  5. Now, wherever you need to update your connection string, call SetUserOverride(). For example, whenever you would want to call My.Settings.ConnectionString1 = "My new string", which is not allowed, you instead call My.Settings.SetUserOverride("ConnectionString1", "My new string").
  6. ' This doesn't work because ConnectionStrings are ReadOnly
    'My.Settings.ConnectionString1 = "My new string"
    
    ' This works!
    My.Settings.SetUserOverride("ConnectionString1", "My new string")
  7. Go to your My Project, Application Settings, and make sure that Save My.Settings on Shutdown is enabled.

Points of Interest

Las Vegas! Walt Disnet World Florida! Maybe I'll think of some REALLY interesting ones later. :)

History

You must Sign In to use this message board.
 
 
Per page   
 FirstPrevNext
Generalusing from a separate project
captainmogo
5:53 26 Jun '09  
I created my tableadapters in a class library project called ConfigurationControl I think this is exactly what I need but I was wondering how do I use it from another project.

I added the Module called Settings.UserOverride.vb to the ConfigurationControl project but now I need to access it from the Main Data acquisition project. Can I access the ConfigurationControl settings class from the other projects? or do I create another sub routine, say in Module1 of the ConfigurationControl project that then calls the SetUserOverride routine.

<pre>
Module Module1
Public Sub SetNewConnectionString(ByVal settingName as string, ByVal value as String)
My.Settings.SetUserOverride(settingName, value)
End Sub
End Module1


With this, I should be able to call the SetNewConnectionString from the Data Acq. project on startup and change the connection string before using any of the table adapters, right?

Thanks for the help. I appreciate it so much
GeneralRe: using from a separate project
mjmeans
20:29 26 Jun '09  
Hmmm.

If you make the MySettings class in your class library Public and make sure the class library is in its own namespace, then you should be able to access it from your other projects, such as OtherClassNamespace.My.Settings.ConnectionString = "server=local;etc". Putting it in another namespace will ensure that the hard coded Settings class name will not conflict with another projects namespace.

If you can't put the library in another namespace for design reasons, then you can add a different public class you can call to access the that libraries settings.
GeneralRe: using from a separate project
captainmogo
3:27 29 Jun '09  
Hi thanks for the response.

This is what I did

After adding the code in this article to the class library (ConfigurationControl), I added a module called Module1 where I created 2 public methods to access the class libraries settings

Module1

Public Sub SetNewConnectionString(ByVal name as string, Byval value as string)
My.Settings.SetUserOverride(name,value)
End Sub

Public Function GetNewConnectionString() as string
Return My.Settings.DatabaseConnection.ToString)
End Function


Now from my other project I call ConfigurationControl.SetNewConnectionString("DatabaseConnection",connString) when change the connection string upon startup.

It seems to be working correctly but I wanted to make sure this was an appropriate solution.


Just out of curiosity, how would i make the settings class of the class library Public as you suggested?
Thanks again for the help
GeneralRe: using from a separate project
mjmeans
8:25 29 Jun '09  
You just click the icon in solution explorer to show all files, then open up the settings.designer.vb file. Change the class to public in settings.designer and also in the code from my article.

Another way you could do this is to pass the connecction string in the NEW. You would do this by changing your table adapters class to Friend (or internal) which would block its access. But then add a new Public class that inherits the table adapter and set its constructor to New(connstr AS String).

Also, if you're looking for a connection string editor, check out my link at the bottom of the article.
GeneralRe: using from a separate project
captainmogo
8:49 29 Jun '09  
mjmeans wrote:
Another way you could do this is to pass the connecction string in the NEW. You would do this by changing your table adapters class to Friend (or internal) which would block its access. But then add a new Public class that inherits the table adapter and set its constructor to New(connstr AS String).


I originally looked at this option but I didnt want to have to do it for every table adapter everytime.

mjmeans wrote:
You just click the icon in solution explorer to show all files, then open up the settings.designer.vb file. Change the class to public in settings.designer and also in the code from my article.


I did this and I am still not able to see the Settings class.
the furthest I can get is otherNameSpace.My.MySettings and then intellisense gives me nothing
GeneralYou might also be interested in...
mjmeans
11:24 17 Apr '09  
Hi. If you like this project, you might also be insterested in a DataConnectionDialog component I am selling. Please see http://mjmeans.com/dcd.aspx[^] for more informaiton.
GeneralHow to control more than one project?
Ricardo Ildefonso
11:05 16 Apr '09  
Hi. Thanks by your code.
But, I have a big problem: my solution have 8 projects and I have ConnectionsStrings in all of then.
When we build a publisher/package to deliver our app to customers we need change the app.config to reflect the new enviroment (the server name and passwords).
But if we change the value of app.config only the main project is afected. The others projects don't update to the new value.

How to fix this issue?
GeneralRe: How to control more than one project?
mjmeans
15:56 16 Apr '09  
That could be complex or simple, depending on how your distribution is created. There's a number of ways to do this, involving command line switches or modifying the sub-apps to read the main apps app.config file. But anything along this line would have problems if the other executables are already running, since the config file may be locked. Note that reading or writing another apps config file could pose problems in Vista if all the config files are not in the same folder. A better idea is to use the registry to flag when each sub-application needs to retrieve an upadated connection string. You would set up a registry key for each sub-application like HKLM/Manufacturer/Product/SubApp1UpdateConnectionString=NEWSTRING. Each sub-application would check in StartUp() for the existance of this key when they start, and if it is found update their own connection string, call My.Settings.Save() and then remove the registry setting so that that it doesn't get re-applied.

If your other apps are DLL's, then there is an additional problem.... since they may have already created their DataAdapters and would then have an OLD copy of the connection string. In this case, you will probably have to save the connection string and then restart the applcaiton unless you add code to each of your DLL's to recreate the DataAdapters.
GeneralThanks!!!
e.frankie10
1:10 18 Mar '09  
I was desperate 'cause I didn't know how to deploy a project containing a little sql server ce.
I spent 3 days Confused trying to avoid errors given by the application when I tried to show in a form data present within the DB.

THANKS A LOT!

Frankie
QuestionUsage in A-level coursework
ultrafez00
2:15 15 Feb '09  
Hi,

Your code is an excellent solution to this problem - and I would like to use it in my A-level coursework for Computing. Would it be possible to e-mail you with regards this?

Thanks very much
Alex
AnswerRe: Usage in A-level coursework
mjmeans
21:28 15 Feb '09  
Sure. Just use the email link at the bottom of this reply and CodeProject will send a private email to me.
NewsC# version works great!
dmageiras
7:16 10 Feb '09  
I converted your great article to C# and it worked great. Here's my version.:

namespace xxx
{
public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{

private static string[] userOverrides =
{
"constring1",
"constring2"
};

private static string userOverrideSuffix = "UserOverride";

public void SetUserOverride(string property, string value)
{
this[property] = value;
}

protected override void OnSettingsLoaded(object sender, System.Configuration.SettingsLoadedEventArgs e)
{
string userProperty = null;
foreach (string appProperty in userOverrides)
{
userProperty = appProperty + userOverrideSuffix;
if (((string)this[userProperty]).Length > 0)
{
this[appProperty] = this[userProperty];
}
}
}

protected override void OnSettingsSaving(object sender, System.ComponentModel.CancelEventArgs e)
{
string userProperty = null;
foreach (string appProperty in userOverrides)
{
userProperty = appProperty + userOverrideSuffix;
this[userProperty] = this[appProperty];
}
}
}
}

GeneralRe: C# version works great!
mjmeans
9:28 10 Feb '09  
Hey. Great! I didn't realize that the normally VB only aplication framework would actually work in C#. Is it actually saving the changed settings on exit, or do you have to set some other properties and handlers in main()?
GeneralRe: C# version works great!
dmageiras
23:35 10 Feb '09  
You should explicitly call Save() method
GeneralRe: C# version works great!
Jlrray
15:32 16 Mar '09  
Do you have an example of how to call this from c#?

Joe
AnswerRe: C# version works great!
dmageiras
6:10 17 Mar '09  
Just call SetUserOverride(...).
For example:
xxx.Properties.Settings.Default.SetUserOverride("constring1",_NewConnectionString);

where:
1. xxx is settings class namespace,
2. "constring1" is your old connection string name,
3. _NewConnectionString is your new connection string.

If you want to persist changes, call Save().
GeneralRe: C# version works great!
Jlrray
7:04 17 Mar '09  
Thanks for confirming that. I've attempted that method, but cannot see the method via intellitype.
AnswerRe: C# version works great!
dmageiras
7:28 17 Mar '09  
Make sure your partial Settings code is in the correct namespace.
GeneralRe: C# version works great!
Jlrray
10:17 17 Mar '09  
Thanks for the information. The correct namespace was:

namespace myapplicationname.properties{

}
GeneralGREAT solution
Charles Carr
11:24 17 Jan '09  
Thanks so much. You explained the situation and gave a terrific solution.
GeneralRe: GREAT solution
mjmeans
18:22 18 Jan '09  
You're welcome. I accept donations. If you have a small country you no longer want, I'll be glad to accept it. Laugh
GeneralReally Great Solution [modified]
George_Bat
3:28 4 Dec '08  
RoseThank You
I think
My.Settings.Item("ConnectionStringName") = NewConnectionString
will make me able to change the connection string with out any classes
Am I right?

George Batres

modified on Thursday, December 4, 2008 9:47 AM

GeneralRe: Really Great Solution
mjmeans
9:26 4 Dec '08  
If you are using a connectionstring which is automatically created by the visual studio, that connection string is an application scoped connection string an is read-only. The command you offer will change the string only in-memory an will not save the connection string. So next time you run the application, the change will be lost unless you have found some other way to recall the change string. Also, since tableadapters reference only the name of the connection string explicitly, then if you have table adapters added to the project when in forms design mode and you load your updated connection strings outside of the 'settings' or 'my.application' classes there is a possibility that a table adapter gets initialized prior to your loadding the new connection string and that will cause the table adapter to use the wrong string.
Generalplease help me i cant know where is the error
seman71
3:07 17 Nov '08  
i do what u ask

my connection is natconnectionstring scop applecation ok
i have one connection string natconnectionstring

i put in the overide like u tell in the place of connection1
i remove connection2

i use the class as u tell me
but nothing



help me please
explan exactly what we do or please

attach simple project that do this class


pleassssssssssss
GeneralRe: please help me i cant know where is the error
mjmeans
21:40 19 Nov '08  
It is probably step 3 that you have not understood. You need to check to see the name of the connection string you used when you created your datasets. This is the name that your strongly types dataset and table adapter expect to use. And it is that name that must be used instead of connectionString1 or connectionString2 in the examples above.

This example ONLY works with strongly typed database access. It could be adapted to use other datasets, but that is project left to the reader to accomplish on their own.


Last Updated 1 Aug 2007 | Advertise | Privacy | Terms of Use | Copyright © CodeProject, 1999-2010