Is this a bug or by design? Settings declared internal when autogenerated???

In relation to this question I had concerning how to access settings that are declared in another project: http://forums.microsoft.com/msdn/ShowPost.aspx PostID=116815#116815, I have some concerns with the way VS2005 beta 2 sets up the Settings file.

When you create a Settings config file, it creates a Settings class that is marked internal to the Properties file. For example, the generated code from one I just created looks like:



namespace ExportImportManager.Properties {
   
   [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
       
        private static Settings defaultInstance = new Settings();
       
        public static Settings Default {
            get {
                return defaultInstance;
            }
        }

 


The problem with this is how can I access these settings from another project I can't overwrite this file and remove the internal modifier since this code is autogenerated every time you add a new setting using the IDE.

Does anyone have other suggestions on how to use 2.0 Settings from another project within your application




Answer this question

Is this a bug or by design? Settings declared internal when autogenerated???

  • virayanna

    Ok, I made the config file by using the ide add file > application config.

    You then end up with a blank App.config as

    < xml version="1.0" encoding="utf-8" >
    <configuration>
    </configuration>

    So for a test I added a property using the ide Settings ...



    <applicationSettings>
            <SettingsStuff.Properties.Settings>
                <setting name="SettingFromIDE" serializeAs="String">
                    <value>ide setting</value>
                </setting>
    </applicationSettings>

     


    Now at this point I also have my custom settings class which looks like...



    namespace SettingsStuff
    {
       public class TestAppSettings : System.Configuration.ApplicationSettingsBase
        {
           private static TestAppSettings myPublicSettings = new TestAppSettings();

           public static TestAppSettings Default { get { return myPublicSettings; } }

           [System.Configuration.ApplicationScopedSetting(),
           System.Configuration.DefaultSettingValue("Default1")]
           public string MyPublicSetting1
           {
               get
               {
                   return (String)this["MyPublicSetting1"];
               }
            }

     


    I then decided to make sure this "MyPublicSetting1" is in app.config so I decided to add it with the designer and it did as I expected (and hoped)...



    <applicationSettings>
            <SettingsStuff.Properties.Settings>
                 <setting name="SettingFromIDE" serializeAs="String">
                    <value>ide setting</value>
                </setting>
                <setting name="MyPublicSetting1" serializeAs="String">
                    <value>public setting from my custom classs</value>
                </setting>
            </SettingsStuff.Properties.Settings>
         </applicationSettings>

     


    I then can access "MyPulicSetting1" by using my custom class outside of the project as...

    SettingsStuff.TestAppSettings.Default.MyPublicSetting1

    Is that they way I should be handling this

    The part I sort of don't like is from within the main settings project I of course could access it as

    SettingsStuff.Properties.Settings.Default.MyPublicSetting1

    I guess it's not too big of a deal, but it would be nice to enforce throughout the whole application just one entry point (using my custom TestAppSettings class).

    Am I close:)

  • Foxcare

    Sorry for the late reply - I haven't been in the office for the past two days (and I'm still not in the office, but just I happened to get my hands on a machine with internet accessSmile)

    Yes, if you want to use the same setting in multiple projects, and you want to use the settings designer, you will have to create the same setting in multiple projects.

    The settings designer was primarily intended to provide an easy and approachable way for assemblies to store their private data (i.e. window locations, MRU lists and such). It also provides other designers in the visual studio IDE a way to store settings (i.e. the windows forms designer can bind properties to settings). This all works on top of the .settings files. A custom tool is then run that generates code from the contents of the .settings file.

    The actual code that is being generated utilizes the new public client configuration API. Our intention was that if you wanted something that the settings designer couldn't provide, you would write code using this API directly. I have included a little code snippet below to show what you'd need to do in order to use this API (nothing magic here).



    public class MyPublicSettings : System.Configuration.ApplicationSettingsBase
    {
       
    private static MyPublicSettings myPublicSettings = new MyPublicSettings();   

       
    public static MyPublicSettings Default  { get { return myPublicSettings; } }

       [System.Configuration.ApplicationScopedSetting(),
       System.Configuration.
    DefaultSettingValue("Default1")]
       public string MyPublicSetting1 { get { return (String)this["MyPublicSetting1"]; } }

       [System.Configuration.ApplicationScopedSetting(),
       System.Configuration.
    DefaultSettingValue("OtherDefault")]
       public string MyOtherPublicSetting { get { return (String)this["MyOtherPublicSetting"]; } }
    }

     



    (Strictly speaking, the shared field/default property accessor are not something that is part of the API, but rather a convenient way to get hold of a common instance of the settings class...)

    The client configuration API is very powerful compared to the old appSettings section/dynamic properties, and provides features such as a pluggable provider support that allows you to use other means than the app/user.config files to store your settings, read/write settings per user, roaming settings, upgrade of settings between application versions. The list goes on. 

    If it is not too late, I would suggest that you'd look into using the client configuration support instead of using your own xml readers. If you look at the class above, it is not exactly rocket science, and it will give you a whole lot of things for free.

    A good starting point if you want to read up on the client config API would be this:
    http://msdn2.microsoft.com/en-us/library/k4s6c3a0.aspx

    Best regards,
    Johan Stenberg



  • ImagineNation

    The more I think about this, the more I think something must not be right.. by 'not right' I mean that I must be doing something that is 'not as intended.'

    I'll try to explain....

    You said you should create the config file using Project-- add file--- application configuration file and keep it as "App.config."   You could then either a) make settings for it using the Settings designer or b) manually add the settings into the config file. In either case, you then have to add the proper accessors to those properties in your custom AppSettings class.

    What seems Soooo goofy though is that this AppSettings class is practically IDENTICAL to the one that the Settings designer will make (Settings.Designer.cs) . Of course it won't be identical if you don't use the Settings designer to add settings to the project, but I almost think that you should work with the Settings designer, because there is no way to really enforce that someone working in the project won't use this option and thus potentially over-write you App.config.

    I guess what I'm trying to get a handle on is that both the Settings designer in the IDE and the stuff you manually want to add to your custom class will BOTH be using the same App.config file. So I'm still sort of wondering if it's better to just not even bother creating your own custom classes and instead just modify the default Settings class from:

    internal sealed partial class Settings   to public class Settings  

    If I do that then everything is a lot less error prone.. when a setting is added using the designer you're done. I don't mind doing things the long-way (actually I prefer to hand code stuff), but I don't like that someone could then come in and add a property using the Settings designer and it alters the same file that you are working from for your custom class(es) (the App.config)

    I'll look over the documenation more but it's really difficult figuring out how this interaction between the ide settings and custom settings classes is supposed to work out.

  • Ddscool

    You can use the SettingsGroupName attribute to share settings between assemblies. Check out http://forums.microsoft.com/msdn/ShowPost.aspx PostID=22844.

    Best regards,
    Johan Stenberg


  • Ryan Bolger

    Ok, I think this is becoming more clear, but ...

    It sounds like you are saying I'm still going to have to declare each property in the Settings of each project even if they are the same property that I'm setting up over and over again In other words I'm going to have to declare "TheSettingIWantToShare" in the Settings options in every project that needs to use that That seems like a lot of work... which I find odd since in 1.1 I could use the ConfigurationManager  to pull out the app.config settings from the main project without much problem. It seems like this becomes more difficult in 2.0 does it not

    It sure seems a lot easier to just delcare the Settings class in the main file you want to share as public (vs keeping it  internal) and viola you have access to those settings from anywhere within the application using the MainNamemspace.Properties.Settings.Default.SharedItem approach.
    I know this isn't the most secure thing, but it sure seems to beat having to add each property in the settings for each project (but then again, I could toally be miscontruing what you're saying:)

    Thanks so much for all your time with this. It's been driving me nuts for days, and I've been googling like crazy:)


  • Dehim

    Thanks Johan for posting back. I appreciate it.

    I've been 'trying' to follow a lot of the info from that link you provided http://msdn2.microsoft.com/en-us/library/k4s6c3a0.aspx  and I have to admit, a lot of is still pretty unclear, but I'm working on it. 

    I created a myappname.exe.config file and then created the class you described above, and it worked fine in regard to loading the settings - Thanks! I also added a UserScopedSetting  and when I called save on the properties it worked great saving the setting to a user.config file.

    Just a  few other questions if you get a chance that are probably in the docs somwhere but I couldn't find them....

    1) What if you wanted to use different config names What if I wanted to load a "myapppropertiesconfig" for my application scoped config instead of creating a 'myappname.exe.config'    (same thing with user.config.. see rationale in next question.)

    2) If I create my own Settings class (as you discribed) and then someone goes and tries to make their own settings class using the IDE settings designer, what should happen In my litt test, it appears that the app config I created manually to be used with "MyPublicSettings" class got completely wiped out! This could be very dangerous so I'm assuming (back to question 1) that I should some how use a different name to stort my app.config settings and my user.config settings - considering that both will get wiped out if someone descides to use the ide to create some settings

  • fg_garda

    Sorry if I wasn't clear; you will still not get access to the settings class in the other project, but by using the SettingsGroupName attribute, you can have two different settings classes defined in two different assemblies that both access the same value in the .config file.

    If you have a settings class in your main executable with a string settings named TheSettingIWantToShare

    namespace TheDefaultNamespace.Properties {

       internal class Settings {

          [
    global::System.Configuration.ApplicationScopedSettingAttribute()]
          
    public string TheSettingIWantToShare { }
       }
    }


    you can put a settings class that looks something like this:

    [SettingsGroupName("TheDefaultNamespace.Properties.Settings")]
    internal class Settings {
       [global::System.Configuration.ApplicationScopedSettingAttribute()]
       
    public string TheSettingIWantToShare { }
    }

    in a dll assembly that you reference from the main application. Since I didn't put a SettingsGroupName attribute on the Settings class in the main executable, it will read its values from the TheDefaultNamespace.Properties.Settings section of the running application's .config files.

    Since I *did* put a SettingsGroupName attribute on the settings class defined in the dll, it will use that to locate the section in the running application's .config files... So, you will have two instances of two different types, one in your main .exe and one in your .dll, but both will get their values from the same location in the .config files...

    And, yes, you will have problems running the beta2 version of VS2005...

    Best regards,
    Johan Stenberg



  • Drew Marsh

    (sorry about the ugly formatting below.. how do I just get back to plain text:)...
     

    Ok, I'm 'almost' there I 'think.' When you say the group name is
    "WhateverNamespaceTheSettingsLiveIn.Properties"

    My Settings namespace in this example  is:
    namespace TestingSettings.Properties {...

    So I tried defining the attribute:
    [global::System.Configuration.SettingsGroupName("TestingSettings.Properties")]

    The question I know have is, how do I access these properties from my other project (reference to project is added)
    I still do not have access to the Settings object when I try:
    TestingSettings.Properties.Settings.

    (complains Settings protected. I know an easy way around this would be to just declare the Setting public, but I'm guessing that's not the correct thing to do.)

    Is the problem that I'm using vs 2005 beta 2 (since I noticed from your thread there is a bug beta 2 ) or am I simply trying to access the settings incorrectly from my other project

    Thanks again Johan, I feel like I'm almost there. I really don't want to have to write my own custom class that serializes xml to an object, so I'd love to have this working.



  • VBRocksLikeMad

    Man, I'm sorry I'm trying to follow what is written here: http://lab.msdn.microsoft.com/productfeedback/viewfeedback.aspx feedbackid=00777ce6-c8ad-4726-885b-4bfc0dfd2a3a

    But I'm lost:(

    You mention in the article

    To get the behavior that you want here, you can use the SettingsGroupNameAttribute. This should(1) replace the namespace.classname part of the full setting name. Please note that the settings designer doesn't directly support this attribute.

    I'd put the attribute on the partial class declaration in the user part of the settings class defined in the class library (the code you see if you press the "View Code" button in the settings designer...). See example below:

    Global.System.Configuration.SettingsGroupName(“WindowsApplication1.Settings”) > _
    Class Settings

    End Class


    I'm not really sure exactly what you are saying above. Is there a concrete example showing this in use somewhere

    Am I supposed to add an attribute [global::System.Configuration.SettingsGroupName("MyApp.Settings")] Somewhere in my Settings.Designer.cs class

    Thanks again for trying to help.

    You also mentioned in that article that you would question the use of needing to have access to settings from different projects. I'm wondering if our team is doing things wrong ... we have a few projects that together form our final assembly. We only want one user.config and one app.config for the project. Isn't it normal to want to have access to these files from anywhere within the application

  • delly_jm

    Actually Step 1 above doesn't really work.. since you can't have partial classes with different accessibilities (can't declare one public and have the other partial class  internal sealed ). Not sure why I eve thought that idea would work.

  • szabti

    If you start sharing the same settings between multiple assemblies, you add implicit dependencies between them, which makes maintaining your system very difficult. I much prefer having an explicit API where I can pass the value of the settings that I want to share. In essence, sharing settings is equivalent to using global variables, which is also something I try to avoid...

    As you probably have noticed, if you put it in the automatically generated file (settings.designer.cs), it will be blown away whenever you make any changes in the settings designer, just as the warning at the top of the file indicates...

    If you really need to share settings, I would recommend adding the group name attribute on the type declaration on the user part of the partial class. 

    To create/navigate to the user part of the file, open the settings designer and press the "View code" button. The file name would most likely be Settings.cs (assuming that you are using the default settings file) and after adding the attribute as indicated in bold it would look roughly something like this:



    // This class allows you to handle specific events on the settings class:
    // The SettingChanging event is raised before a setting's value is changed.
    // The PropertyChanged event is raised after a setting's value is changed.
    // The SettingsLoaded event is raised after the setting values are loaded.
    // The SettingsSaving event is raised before the setting values are saved.
    [global::System.Configuration.SettingsGroupName("WhateverNamespaceTheSettingsLiveIn.Properties")]

    internal
    sealed partial class Settings {
       ....

     


    Regarding your questions about multiple app.config/user.config files; if you have multiple assemblies that define settings classes, in an executable, they will all share the same app.exe.config and user.config file(s). The name of the files depend on the application that is executing, not on the assembly name of the assembly where the settings class is defined  (*).

    Each settings class will read/write it's values in it's own sections within the file(s).

    The name of the section in the .config file is based on:
    1) The value of the SettingsGroupName attribute of the settings class (if any), which is what we rely on here in order to share the setting value between multiple settings classes/projects
    2) If no SettingsGroupName attribute is present, the namespace qualified name of the settings class.
     

    (*) This is almost true, and you have to do some fairly advanced stuff for it to not be true. For a more exhaustive explanation on how the file paths are computed, you can check out Raghavendra's Client Config FAQ. The main gotcha is that you can spin up additional app domains with different evidence, which will mean that depending on from which app domain you are getting the settings, you may get different values. Again, if this doesn't make sense to you, don't worry - like I said, it is a fairly advanced scenario that most mortals don't have to care about :)

    Best regards,
    Johan Stenberg



  • William Gates

    1) The default settings provider (which happens to be the LocalFileSettingsProvider) uses the standard configuration system to locate the setting values. The configuration has special knowledge about the appropriate file names, and while it is possible to change the configuration file names (by spinning up additional app domains) it is non-trivial, and not something I would recommend just to accomplish this. If you really want to use different file names, I'd recommend creating your own SettingsProvider. Again, Raghavendra's Client Config FAQ is an excellend source of information... (check out the "You said user.config files go in the user data path. How can I locate the file Are there multiple files for an application or just one " and the "Why is the path so obscure Is there any way to change/customize it " sections). Hopefully you won't have to do this after reading 2) Smile

    2) I believe that you have made the all to common mistake of either manually adding the myappname.exe.config file in the bin folder or added it to your project. Visual Studio assumes that the configuration file name is app.config in the project. This file will be automatically renamed and copied to the bin folder as part of the build. See http://forums.microsoft.com/msdn/ShowPost.aspx PostID=107411.

    Best regards,
    Johan Stenberg

  • WantaBe

    /bump

    Just curious.. So close to having the issue resolved. Follow up on my last post would be great if you get a chance. Thanks.

    In the meantime, I went ahead and am using my own xml file readers etc to do all of this. Would be nice to be able to use the settings the way they were intended though.

  • Jeremy613

    Johan, you still around by any chance:) I hate to be a pest, but I'm sort of stuck with having to make a decision soon on how I want to refactor getting our app and user settings under the 2.0 framework, so I'm bumping this thread in case Johan or anyone else has a few suggestions in reagard to my last couple post before this one.

    The current options I'm debating about...

    1) Simply change the delcaration of the main app Settings class from internal sealed to public.
    •  + super easy. Can use Settings designer. No having to code property accessors. Syntax is the same across  all projects just as it is from within the main project.
    •   -  Not sure of the negative, other than this can't be what MS had intended. I guess there could be a potential problem way down the line if you decided to use the main project in another solution and forgot that you set the Settings to public which potentially could be abused.

    2)  Create my own public Settings class that extends ApplicationSettingsBase and use the ide to add---> new item---> app configuration file (creates App.config)
    •  + Can access settings across multiple projects that are declared in app.config. Didn't have to modify Settings class from internal to public
    •  -  Things might get messed up if another user goes to the Settings designer and starts adding properties.. it will modify your App.config file. If you then decide you'd rather modify the settings from the designer and still use your custom class, you basically are just duplicating the class the settings designer is building for you in the background (although it's building it with only internal access).

    3) Create my own classes that serialize from xml files and are completely independent of the Settings of Visual Studio.
    •  + You aren't tied to having to understand the infrastructure of visual studio setttings.
    •  - You don't get the ease of development using the .net 2.0 infrastructure. You have to code the xml serialization/deserialization. You have to determine where to save files, where to load from etc.You also still need to code the accessor methods and the xml files.



  • Is this a bug or by design? Settings declared internal when autogenerated???