Loading the WCF configuration from different files on the client side

A common problem in WCF that many people face is the impossibility of loading the client configuration from different configuration files. This is a common scenario  when the developer wants to deploy some binaries with along with an independent configuration file (Which may be in a resource file also) to avoid modifying the main configuration file. A weeks ago, I described a easy workaround to use the external configuration files through the use of the configSource attribute (A mechanism provided by .NET). However, that approach requires several configuration files to configure an entire WCF channel, at least three files (client section, bindings and behaviors).

Another approach, which is less common and I will describe in this post, requires some custom code to extend the ChannelFactory<T> class.

The ChannelFactory<T> provides a virtual method "CreateDescription" that can be overridden to create a ServiceEndpoint.

 

//

// Summary:

//    Creates a description of the service endpoint.

//

// Returns:

//    The System.ServiceModel.Description.ServiceEndpoint of the service.

//

// Exceptions:

//   System.InvalidOperatorException:

//    The callback contract is null but the service endpoint requires one that

//    is non-null.

protected override ServiceEndpoint CreateDescription();

The default implementation of this method basically tries to load the endpoint configuration from the default configuration file (The file configured for the default AppDomain). So, the workaround here is to override that method and load the configuration from another file. It seems to be pretty easy to do at first glance, but as you will see next, it requires a lot of plumbing code to make it work.

The first step is to derive our custom channel class from the ChannelFactory<T> class and add an argument in the constructor to specify a different configuration file.

/// <summary>

/// Custom client channel. Allows to specify a different configuration file

/// </summary>

/// <typeparam name="T"></typeparam>

public class CustomClientChannel<T> : ChannelFactory<T>

{

  string configurationPath;

 

  /// <summary>

  /// Constructor

  /// </summary>

  /// <param name="configurationPath"></param>

  public CustomClientChannel(string configurationPath) : base(typeof(T))

  {

    this.configurationPath = configurationPath;

    base.InitializeEndpoint((string)null, null);

  }

As you can see, a call to the method InitialiazeEndpoint of the base class is required. That method will automatically call to our CreateDescription method to configure the service endpoint.

/// <summary>

/// Loads the serviceEndpoint description from the specified configuration file

/// </summary>

/// <returns></returns>

protected override ServiceEndpoint CreateDescription()

{

   ServiceEndpoint serviceEndpoint = base.CreateDescription();

 

   ExeConfigurationFileMap map = new ExeConfigurationFileMap();

   map.ExeConfigFilename = this.configurationPath;

 

   Configuration config = ConfigurationManager.OpenMappedExeConfiguration(map, ConfigurationUserLevel.None);

   ServiceModelSectionGroup group = ServiceModelSectionGroup.GetSectionGroup(config);

 

   ChannelEndpointElement selectedEndpoint = null;

 

   foreach (ChannelEndpointElement endpoint in group.Client.Endpoints)

   {

      if (endpoint.Contract == serviceEndpoint.Contract.ConfigurationName)

      {

        selectedEndpoint = endpoint;

        break;

      }

    }

 

    if (selectedEndpoint != null)

    {

      if (serviceEndpoint.Binding == null)

      {

        serviceEndpoint.Binding = CreateBinding(selectedEndpoint.Binding, group);

      }

 

      if (serviceEndpoint.Address == null)

      {

        serviceEndpoint.Address = new EndpointAddress(selectedEndpoint.Address, GetIdentity(selectedEndpoint.Identity), selectedEndpoint.Headers.Headers);

      }

 

      if (serviceEndpoint.Behaviors.Count == 0 && selectedEndpoint.BehaviorConfiguration != null)

      {

        AddBehaviors(selectedEndpoint.BehaviorConfiguration, serviceEndpoint, group);

      }

 

      serviceEndpoint.Name = selectedEndpoint.Contract;

    }

 

    return serviceEndpoint;

 

}

 

CreateDescription is the core method where we create the service endpoint using the configuration file specified in the constructor method.

And the last step, is to use our custom channel in the client application instead of the base channel provided by WCF.

CustomClientChannel<ICalculator> channel = new CustomClientChannel<ICalculator>("OtherConfig.config");

ICalculator client = channel.CreateChannel();

The code below uses the ICalculator contract  that comes with the WCF sdk samples.

You can download the complete sample here

 

 

 

Comments

# Link Listing - October 19, 2007

Friday, October 19, 2007 11:36 PM by Christopher Steen

Link Listing - October 19, 2007

# [WCF] Caricare la configurazione da un file diverso lato client

Monday, October 22, 2007 9:06 AM by Diario di Bordo

Ottimo post di Pablo "Cibrax" Cibraroche spiega come creare un client in grado di leggere la configurazione

# re: Loading the WCF configuration from different files on the client side

Thursday, October 25, 2007 2:28 AM by Eddie Chu

Nice approach to create the client channel by loading a non-default application configuration file!

However, I just found a tiny problem from your sample that if the endpointConfigurationName is explicitly specified, an InvalidOperationException will be thrown to tell me that the specified endpoint element cannot be found. Any ideas?

# re: Loading the WCF configuration from different files on the client side

Thursday, October 25, 2007 8:51 AM by cibrax

Hi Eddie, I am not sure about that problem, it must  be bug in code since I did not test it very well for all scenarios. I will take a look more in detail, thanks for the feedback!!.

# re: Loading the WCF configuration from different files on the client side

Wednesday, December 05, 2007 3:58 PM by cibrax

I just uploaded a new version of this code that fixes the non-default configurationName bug.

Thanks

Pablo.

# re: Loading the WCF configuration from different files on the client side

Friday, December 07, 2007 5:07 PM by Timur Fanshteyn

One more small bug.

In AddBehaviours() function. If number of EndpointBehaviors is 0, the function will fail.

I had to add

if (group.Behaviors.EndpointBehaviors.Count == 0)

               return;

at the beginning of the function to solve the issue.

----

Thanks a lot for the functionality. Works great.

# re: Loading the WCF configuration from different files on the client side

Tuesday, December 11, 2007 8:30 AM by Patricio Ogaz D.

Nice article, a excelent way to solved this !!!

I use this code for testing porpouse, witah a standard service, but I receive a Exception in the CreateDescription() method.

Then I debug and retouch a line for the call to AddBehaviors , I adding this code at the end of the conodition:

&& selectedEndpoint.BehaviorConfiguration != "")

Because when the behavior isn't set, the behavior it's empty, then the app try to add the configuration and trhow a exception.

The article it's very good and usefull, thanks.

Patricio.

# Merge di file di configurazione in WCF

Saturday, December 15, 2007 9:56 AM by BlogServiceHost.Create()

Qualche tempo fa avevo letto questo post di Pablo Cibraro (aka Cibrax) e mi ero ripromesso di fare la

# [WCF] Merge di file di configurazione

Saturday, December 15, 2007 12:16 PM by BlogServiceHost.Create()

Qualche tempo fa avevo letto questo post di Pablo Cibraro (aka Cibrax) e mi ero ripromesso di fare la

# re: Loading the WCF configuration from different files on the client side

Tuesday, February 12, 2008 10:21 AM by eprystupa

Is the source code for the sample still available? The posted URL seems to be down...

Thanks!

-Eugene

# re: Loading the WCF configuration from different files on the client side

Thursday, April 17, 2008 4:55 AM by naziya

Extremely useful information. With some minor changes I could use this solution to make a C++ client to talk with WCF Server

# re: Loading the WCF configuration from different files on the client side

Monday, April 28, 2008 12:25 PM by Gavin S

You rock man....  the WCF team needs to solve this limitation..  I'm writing addons, and can't modify the applications config file.. thanks a ton!

# re: Loading the WCF configuration from different files on the client side

Friday, May 30, 2008 9:48 AM by Kevan Brewer

Excellent! Thanks for that, I'm implementing a plug-in component that uses WCF and the main exe does not need to know anything about the endpoint or even WCF for that matter.

I find it hard to believe that this isn't standard functionality in WCF!

I had to modify the CreateDescription() method to cope with no 'Behavior' entries as follows:

if (serviceEndpoint.Behaviors.Count == 0 && !string.IsNullOrEmpty(selectedEndpoint.BehaviorConfiguration))

{

   AddBehaviors(selectedEndpoint.BehaviorConfiguration, serviceEndpoint, group);

}

# re: Loading the WCF configuration from different files on the client side

Monday, August 11, 2008 10:42 AM by Leonardo

Hi. First of all, great work!

Can you tell me how can I close the channel using this approach?

The service interface doesn't have the close() method.

Thanks,

Leonardo.

# re: Loading the WCF configuration from different files on the client side

Wednesday, October 29, 2008 2:13 PM by Myxamopiyc

Excellent!

Thanks!

I added:

1) if (group.Behaviors.EndpointBehaviors.ContainsKey(behaviorConfiguration)){ ...

2) private Binding GetBinding(string bindingName){switch(bindingName.ToLower())...case "wshttpbinding":return new WSHttpBinding);...}}

and call it from

private Binding CreateBinding(string bindingName, ServiceModelSectionGroup group)

# re: Loading the WCF configuration from different files on the client side

Tuesday, November 18, 2008 6:58 PM by George

Is it possible to extend the DuplexChannelFactory<T> in a similar way? I tried it but this didn't work as I can't assign the callBackObject anywhere in a protected/public property/method.

# re: Loading the WCF configuration from different files on the client side

Friday, February 06, 2009 4:28 AM by Ram

This is fantastic article . This code i slightly changed to load from GAC. In my project i faced one issue.I am writing one feature in a class library which is consuming WCF.I could n't load the Config file since my dll is Gaced. With this code i achieved the solution thanks..

# re: Loading the WCF configuration from different files on the client side

Friday, February 06, 2009 12:55 PM by Chris Rothery

Thank you, this is awesome.

I couldn't have my own config attached to the main application so this has saved my life (not literally..!)

# re: Loading the WCF configuration from different files on the client side

Friday, February 20, 2009 2:13 PM by Steve

Thanks so much!  I have been searching for hours and came across this.  As with one of the commenters above I had to add a check for when there are 0 behaviors, but after that it worked fine.

# re: Loading the WCF configuration from different files on the client side

Monday, March 30, 2009 4:57 AM by fayssal

Hi,

Thanks for the code!

I have a problem with the length of arrays allowed from the client when using this code. Apparently the creation of the binding does not parse the all the attributes correctly.

Regards.

# re: Loading the WCF configuration from different files on the client side

Monday, March 30, 2009 11:33 AM by Duke

Amazing code! many thanks!

# re: Loading the WCF configuration from different files on the client side

Friday, May 15, 2009 3:26 PM by Nima

There's a new API for this in the new .NET 4.0 preview. Class full name: System.ServiceModel.Configuration.ConfigurationChannelFactory.

# Invocare wcf services da un LoadTest plugin

Monday, May 25, 2009 8:09 AM by smartinz's blog

Invocare wcf services da un LoadTest plugin

# re: Loading the WCF configuration from different files on the client side

Friday, June 12, 2009 6:22 AM by Adriana

Hi,

Thanks for your post, helped me a lot. I found another bug tho, besides the one with Behaviour. If in the config file are multiple endpoints each one with its binding, it takes always the first binding no matter of the endpoint.

Fixed it like this:

//in CreateDescription() modify

if (serviceEndpoint.Binding == null)

               {

                   serviceEndpoint.Binding = CreateBinding(selectedEndpoint.Binding, selectedEndpoint.BindingConfiguration, serviceModeGroup);

               }

...

  if (serviceEndpoint.Behaviors.Count == 0 && !String.IsNullOrEmpty(selectedEndpoint.BehaviorConfiguration))

               {

                   AddBehaviors(selectedEndpoint.BehaviorConfiguration, serviceEndpoint, serviceModeGroup);

               }

  /// <summary>

       /// Configures the binding for the selected endpoint

       /// </summary>

       /// <param name="bindingName"></param>

       /// <param name="group"></param>

       /// <returns></returns>

       private Binding CreateBinding(string bindingName, string bindingConfiguration, ServiceModelSectionGroup group)

       {

           IBindingConfigurationElement be = null;

           BindingCollectionElement bindingElementCollection = group.Bindings[bindingName];

           if (bindingElementCollection.ConfiguredBindings.Count > 0)

           {

               foreach (IBindingConfigurationElement bindingElem in bindingElementCollection.ConfiguredBindings)

               {

                   if (string.Compare(bindingElem.Name, bindingConfiguration) == 0)

                   {

                       be = bindingElem;

                       break;

                   }

               }

               Binding binding = null;

               if (be != null)

               {

                   binding = GetBinding(be);

                   be.ApplyConfiguration(binding);

               }

               return binding;

           }

           return null;

       }

# Client Configuration in WCF 4.0

Tuesday, September 08, 2009 11:17 AM by Pablo M. Cibraro (aka Cibrax)

As Dr Nick announced in this post , WCF 4.0 will ship with a new feature to configure a client channel

# WCF Shortcomings and Dark Sides

Thursday, September 17, 2009 10:32 AM by SeeSharp

WCF Shortcomings and Dark Sides

# Ivan Krivyakov &raquo; WCF Configuration: Thou Shalt Not Hard Code

Pingback from  Ivan Krivyakov &raquo; WCF Configuration: Thou Shalt Not Hard Code

# GoTinker &raquo; Minimal WCF server/client WITHOUT app.config

Pingback from  GoTinker &raquo; Minimal WCF server/client WITHOUT app.config

# re: Loading the WCF configuration from different files on the client side

Friday, November 18, 2011 11:20 AM by Chandr

This awesome.. saved time and got functionality done in sharepoint.. great.

Leave a Comment

(required) 
(required) 
(optional)
(required)