WCF Configuration - Split it out of app.config

28,232

Solution 1

I have a tendency to programatically configure all my service settings.

My clients aren't really the type to understand XML and have asked me make configuration files more like the old INI style.

This is easy to do (reading INI file code not included):

        // create the URI which is used as the service endpoint
        Uri tcpBaseAddress = new Uri(
                string.Format("net.tcp://{0}:{1}",
                    LocalIPAddress.ToString(), GeneralPortNumber));

        // create the net.tcp binding for the service endpoint
        NetTcpBinding ntcBinding = new NetTcpBinding();
        ntcBinding.Security.Mode = SecurityMode.None;
        System.ServiceModel.Channels.Binding tcpBinding = ntcBinding;

        // create the service host and add the endpoint
        Host = new ServiceHost(typeof(WordWarService), tcpBaseAddress);

Since we can configure the host (and client, for that matter) programatically there is nothing keeping you from supplying the settings in any manner you choose (database, xml, crazy text file, etc).

Solution 2

You can separate out your WCF configuration using configSource. Instructions here:

http://weblogs.asp.net/cibrax/archive/2007/07/24/configsource-attribute-on-system-servicemodel-section.aspx

Another option is to configure your WCF services programatically.

Solution 3

using System;
using System.Configuration;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Configuration;

namespace ConsoleHost
{
    public class CustomServiceHost : ServiceHost
    {
        public CustomServiceHost(string customConfigPath, Type serviceType, 
            params Uri[] baseAddresses)
        {
            CustomConfigPath = customConfigPath;
            var collection = new UriSchemeKeyedCollection(baseAddresses);
            InitializeDescription(serviceType, collection);
        }

        public string CustomConfigPath { get; private set; }

        protected override void ApplyConfiguration()
        {
            if (string.IsNullOrEmpty(CustomConfigPath) ||
                !File.Exists(CustomConfigPath))
            {
                base.ApplyConfiguration();
            }
            else
            {
                LoadConfigFromCustomLocation(CustomConfigPath);
            }
        }

        void LoadConfigFromCustomLocation(string configFilename)
        {
            var filemap = new ExeConfigurationFileMap
            {
                ExeConfigFilename = configFilename
            };
            Configuration config = ConfigurationManager.
                OpenMappedExeConfiguration(filemap, ConfigurationUserLevel.None);

            var serviceModel = ServiceModelSectionGroup.GetSectionGroup(config);

            bool loaded = false;
            foreach (ServiceElement se in serviceModel.Services.Services)
            {
                if (se.Name == Description.ConfigurationName)
                {
                    LoadConfigurationSection(se);
                    loaded = true;
                    break;
                }
            }

            if (!loaded)
                throw new ArgumentException("ServiceElement doesn't exist");
        }
    }
}

After this class just use it as you would normally use it to initialize the service host

myServiceHost = new CustomServiceHost(ConfigFileName, typeof(QueryTree));

myServiceHost.Open();

Solution 4

I found this article that may help you out. I have not tried it, but it seems fairly straightforward.

http://weblogs.asp.net/cibrax/archive/2007/07/24/configsource-attribute-on-system-servicemodel-section.aspx

" The configSource attribute was firstly introduced in .NET framework 2.0 to support external configuration files. This attribute can be added to any configuration section to specify an external file for that section.

Unfortunately, the system.serviceModel section group does not support this attribute. If you try to add it, you will receive the following exception:

The attribute 'configSource' cannot be specified because its name starts with the reserved prefix 'config' or 'lock'

What I found out is that you can use this attribute on the different sections under system.serviceModel such as services, behaviors or bindings. "

Solution 5

I've been longing to do the same - basically even one step further: put my WCF config in a database table (since I can change that - can't access the file system on my hosted provider to change config files :-().

Unfortunately, this seems less than simple.....

Basically, it boils down to having to write your own custom "ServiceHost" descendant which can handle the configuration as needed.

Here's an example of loading WCF configuration from a custom config location.

This might get you going? I'm still hoping I'll be able to figure out the "loading my config from a database table" some day..... just need to quiet week at work, I guess :-)

Share:
28,232
ZombieSheep
Author by

ZombieSheep

UK based .Net developer and gadget freak. My tweets | About reputation on StackOverflow

Updated on July 09, 2022

Comments

  • ZombieSheep
    ZombieSheep almost 2 years

    I have a specific requirement to remove all client WCF configuration (<system.serviceModel>) out of the main app.config file, and into a separate XML file. The behaviour I would like to see is similar to that available in the appSettings section using the File="" directive. In fact, I'd ideally like to be able to specify a separate file for each consumed service...

    I know I can build a custom ChannelBuilder factory that reads config data from an XML file (or a series of them), but I would prefer to still have the config data "auto-discovered" by the client.

    Some basic Google searches seem to suggest this is not possible, but I wanted to get the view from SO - does anyone here know something I haven't been able to find? :)

    Edit ::

    Tim Scott and davogones both came up with a possible suggestion, but one which relies on splitting the component sections of the system.serviceModel section out to separate files. Although this isn't quite what I'm looking for (I'd like to define each service and its associated elements discretely, one file per service), it is an option. I'll investigate and let you know what I thought.

    • Admin
      Admin almost 14 years
      check System.ServiceModel.Configuration.ConfigurationChannelFactor‌​y
    • aruno
      aruno over 11 years
      warning: as soon as you do this you lose intellisense which was greatly improved in .NET 4 even to the point of parsing your bindings and telling you things that are missing
  • marc_s
    marc_s over 15 years
    Are you sure?? I don't think this works - the "configSource" attribute isn't defined on all elements in the app.config/web.config, as far as I know....
  • davogones
    davogones over 15 years
    This doesn't work. You can only use configSource on sections, not sectionGroups.
  • Sailing Judo
    Sailing Judo over 15 years
    The only thing thats hardcoded above is the TCP binding. You can easily read all the other data from another source, which is what I do.
  • andriy
    andriy almost 15 years
    This only works on subsections of system.serviceModel (e.g. binding, client, etc.). It doesn't work on system.serviceModel itself.
  • Cheeso
    Cheeso almost 15 years
    re: "less than simple." The custom ServiceHost code is available, more or less boilerplate.
  • RichardOD
    RichardOD over 14 years
    Yes- but surely that is good enough? weblogs.asp.net/cibrax/archive/2007/07/24/…
  • BozoJoe
    BozoJoe about 14 years
  • wmarquez
    wmarquez about 13 years
    Documentation on how this might be provided would be appreciated.
  • Kir
    Kir over 12 years
    Agreed. This answer is too vague to be useful.
  • Noldorin
    Noldorin over 12 years
    +1 for this. I actually dislike the WCF XML configuration on principle. Lots of boilerplate, incomprehensible options, and a very verbsoe syntax. Let me do it in code with Intellisense, I don't have to learn a new format, and all is good. I can still delegate things like port number to a custom setting anyway, as @SailingJudo hints. :-)