1

We are working on a legacy C# enterprise app. Its client uses several web services, whose URLs, among lots of other settings, are read from the local app.config file. We want to migrate these settings into a global DB to simplify their management. However, I can't figure out how (and whether) it is possible to migrate the web service URLs. These are read from the service client code generated by VS and I can't seem to find a way to tell VS to use a different settings provider than the one generated into Settings.Designer.cs .

We can overwrite the service facade's Url property with the value we want, after it is created - this is the solution currently used in several places in the code. However, I wouldn't like to touch every part of our codebase where any of these services is used (now and in the future). Even less would I like to modify generated code.

There has to be a better, cleaner, safer solution - or is there?

Btw our app runs on .NET 2.0 and we won't migrate to newer versions of the platform in the foreseeable future.

Péter Török
  • 114,404
  • 31
  • 268
  • 329
  • 3
    It would appear that you need a [Settings Provider](http://msdn.microsoft.com/en-us/library/system.configuration.settingsprovider.aspx) which can use a database to store the settings in. – John Saunders Feb 01 '13 at 18:09
  • @John, that's how it looks like indeed. Just how can I tell VS to use my SettingsProvider in the generated web service client code? – Péter Török Feb 01 '13 at 20:47
  • 1
    @PéterTörök Perhaps these links help http://www.codeproject.com/Articles/20917/Creating-a-Custom-Settings-Provider and http://msdn.microsoft.com/en-us/library/8eyb2ct1.aspx and http://www.codeproject.com/Articles/136152/Create-a-Custom-Settings-Provider-to-Share-Setting – Yahia Feb 04 '13 at 08:56
  • Do you already have a custom `SettingsProvider` class? – Alex Filipovici Feb 04 '13 at 14:35
  • @Yahia, thanks, the links provided some guidance to the right direction (alas, at points unclear and/or incorrect). – Péter Török Feb 04 '13 at 16:51

1 Answers1

1

The Refernce.cs file that is generated by the Visual Studio indicates that the URL of the webservice will be retrieved from the settings:

this.Url = global::ConsoleApplication1.Properties.
    Settings.Default.ConsoleApplication1_net_webservicex_www_BarCode;

I believe that John Saunders gave you a wonderful suggestion in his comment. You need a SettingsProvider class which:

...defines the mechanism for storing configuration data used in the application settings architecture. The .NET Framework contains a single default settings provider, LocalFileSettingsProvider, which stores configuration data to the local file system. However, you can create alternate storage mechanisms by deriving from the abstract SettingsProvider class. The provider that a wrapper class uses is determined by decorating the wrapper class with the SettingsProviderAttribute. If this attribute is not provided, the default, LocalFileSettingsProvider, is used.

I don't know how much you have progressed following this approach, but it should go pretty straighforward:

  1. Create the SettingsProvider class:

    namespace MySettings.Providers
    {
        Dictionary<string, object> _mySettings;
    
        class MySettingsProvider : SettingsProvider
        {
            // Implement the constructor, override Name, Initialize, 
            // ApplicationName, SetPropertyValues and GetPropertyValues (see step 3 below)
            // 
            // In the constructor, you probably might want to initialize the _mySettings 
            // dictionary and load the custom configuration into it.
            // Probably you don't want make calls to the database each time
            // you want to read a setting's value
        }
    }
    
  2. Extend the class definition for the project's YourProjectName.Properties.Settings partial class and decorate it with the SettingsProviderAttribute:

    [System.Configuration.SettingsProvider(typeof(MySettings.Providers.MySettingsProvider))]
    internal sealed partial class Settings
    {
        //
    }
    
  3. In the overridden GetPropertyValues method, you have to get the mapped value from the _mySettings dictionary:

    public override SettingsPropertyValueCollection GetPropertyValues(
        SettingsContext context,
        SettingsPropertyCollection collection)
    {
        var spvc = new SettingsPropertyValueCollection();
        foreach (SettingsProperty item in collection)
        {
            var sp = new SettingsProperty(item);
            var spv = new SettingsPropertyValue(item);
            spv.SerializedValue = _mySettings[item.Name];
            spv.PropertyValue = _mySettings[item.Name];
            spvc.Add(spv);
        }
        return spvc;
    }
    

As you can see in the code, in order to do that, you need to know the setting name as it was added in the app.config and the Settings.settings when you have added the reference to the web service (ConsoleApplication1_net_webservicex_www_BarCode):

<applicationSettings>
    <ConsoleApplication30.Properties.Settings>
        <setting name="ConsoleApplication1_net_webservicex_www_BarCode"
            serializeAs="String">
            <value>http://www.webservicex.net/genericbarcode.asmx</value>
        </setting>
    </ConsoleApplication30.Properties.Settings>
</applicationSettings>

This is a very simple example, but you might use a more complex object to store the configuration information in conjunction with other properties available in the context such as item.Attributes or context in order to get the proper configuration value.

Community
  • 1
  • 1
Alex Filipovici
  • 31,789
  • 6
  • 54
  • 78
  • Thanks Alex, this really cleared things up! I was trying and failing the whole day to make my settings provider work, due to the sad fact that the material I found so far was contradicting and/or simply incorrect. Your step 2 above was the key which I haven't found anywhere else. It has earned you the bounty, but I can only award it tomorrow... – Péter Török Feb 04 '13 at 16:45
  • @PéterTörök, I'm glad it helped. Good luck with your implementation! – Alex Filipovici Feb 04 '13 at 16:53