Is there an easy way to enumerate the bindings listed in configuration?

This question has crossed my desk in a couple of different forms:

  • Is there an easy way to enumerate the bindings listed in configuration?
  • How do I enumerate the available bindings?
  • How do I enumerate all of the bindings exposed in config and their underlying runtime binding type?
  • etc., etc.

 

Before I go further into answering this question, I need to define a few terms.

  • Binding - A "standard binding", which translates to a predefined collection of binding elements (i.e. not a custom binding).
  • Runtime binding - The binding object used by the WCF at runtime as part of an endpoint. When binding appears without "runtime" specified, this references the configuration object responsible for exposing the runtime binding to the WCF configuration system.
  • Configured binding - A named configuration entry under a binding's element. WCF configuration can reference a binding that does not include a configured binding, which results in retrieving the default settings for the given binding.
  • "Available to my app" - Exists in the configuration merged view created when opening the application.config file associated with "my app".

 

Now, without further ado, the discussion begins.

 

When I get this question, I first respond with "Why do you need to accomplish this?" I do understand the general concept behind needing to enumerate bindings (and all of WCF's configuration extension points); however, the desired application of the information significantly changes the implementation requirements. I also find that some people looking to enumerate the bindings available on a machine really want to enumerate the configured service endpoints for a given service or something similar. For the purpose of this posting I will explore the following four scenarios (the most common answers to my response):

1. Enumerate all of the bindings available to my app

2. Enumerate all of the configured bindings available to my app

3. Enumerate all of the configured endpoints exposed by a service

4. Enumerate all of the configured client endpoints available to my app

 

Please allow me just one last tangent before I go into each scenario individually. Enumerating the bindings inside of WCF configuration requires some details about how binding extensions plug into the WCF configuration system. The complete details live outside the scope of this post and I plan on including a future post on the topic of how to write your own binding extension and plug it into the WCF configuration system. To that extent, I will keep the details on the WCF configuration extension mechanisms to a minimum in this post.

 

Enumerate all of the bindings available to my app

The specific scenario I hear most for this question involves creating a dynamically configurable service / client. Essentially, the enumeration will fill some type of editor control for setting the binding on an endpoint (think wizard type application here). The solution I describe for this scenario actually accomplishes two things. First, it discovers all of the binding configuration element names available to an application. Second, it examines each of the bindings found and discovers the underlying runtime binding associated with that configuration element.

 

The solution becomes straight forward when you understand that all of the WCF configuration extensions (including those built into the WCF product) are registered in one of three collections under the Extensions configuration section in the System.ServiceModel configuration section group. For this post I will focus on the BindingExtensions collection. These extension collections contain a number of add elements that include a name and type property. The name property corresponds to the xml element name that references this binding. The type property corresponds to the type that knows how to deserialized the configuration XML for this binding.

<configuration>

  <system.serviceModel>

    <extensions>

      <bindingExtensions>

        <add name="basicHttpBinding" type="System.ServiceModel.Configuration.BasicHttpBindingCollectionElement, System.ServiceModel, ..."/>

      </bindingExtensions>

    </extensions>

  </system.serviceModel>

</configuration>

 

The first part of this solution simply involves enumerating the entries in the BindingExtensions collection and capturing each entries' name.

 

To understand the second part of the solution, you need to understand that the WCF BindingsSection configuration section uses the name property of each entry and creates a configuration property of the same name for each entry. This allows us to get the BindingCollectionElement base class for each binding registered with the system. To facilitate enumerations like this, BindingCollectionElement contains a helper property (get only), BindingType, which returns the type of the underlying runtime binding configured by this extension.

<configuration>

  <system.serviceModel>

    <bindings>

      <basicHttpBinding/>

    </bindings>

  </system.serviceModel>

</configuration>

 

Here is a quick bit of code that accomplishes both of these items and displays the information to the console:

static void EnumerateAllAvailableBindings()

{

    Configuration appConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

    ServiceModelSectionGroup serviceModel = ServiceModelSectionGroup.GetSectionGroup(appConfig);

    BindingsSection bindings = serviceModel.Bindings;

    Console.WriteLine("Xml Element Name : Underlying Binding Type");

    foreach (ExtensionElement bindingExtension in serviceModel.Extensions.BindingExtensions)

    {

        Console.WriteLine("{0} : {1}",

            bindingExtension.Name,

            bindings[bindingExtension.Name].BindingType.FullName);

    }

}

 

Enumerate all of the configured bindings available to my app

Like the previous scenario, this specific scenario often involves some sort of dynamically configurable application (again think wizard). An important distinction to make for this solution revolves around its completeness. This solution only discovers configured bindings and ignores bindings that do not include configured instances. If your scenario requires that you find all possible bindings, or even all referenced bindings, you need to go further. For the former (all possible bindings), you should include the above scenario to first grab all possible default bindings available, and then look for specific configured instances of each of those bindings. For the later (all referenced bindings), you really need a solution more like the following two that enumerate the service and/or client endpoints in config and discover what bindings each endpoint references.

 

Focusing on just solving the problem of enumerating just the configured bindings available to an application, it starts with the above solution of getting each registered binding element name, and then getting the BindingCollectionElement base class from the BindingsSection configuration section. To facilitate these types of enumerations, the BindingCollectionElement base class has a helper property (get only) ConfiguredBindings. This returns a collection of IBindingConfigurationElement interfaces, which allows us to query the configured binding for its configuration name.

<configuration>

  <system.serviceModel>

    <bindings>

      <basicHttpBinding>

        <binding name="myBinding" />

      </basicHttpBinding>

    </bindings>

  </system.serviceModel>

</configuration>

 

 

Here is a quick bit of code that accomplishes this task and displays the information to the console:

static void EnumerateAllConfiguredBindings()

{

    Configuration appConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

    ServiceModelSectionGroup serviceModel = ServiceModelSectionGroup.GetSectionGroup(appConfig);

    BindingsSection bindings = serviceModel.Bindings;

    Console.WriteLine("Xml Element Name : Underlying Binding Type : Configuration Name");

    foreach (ExtensionElement bindingExtension in serviceModel.Extensions.BindingExtensions)

    {

        foreach (IBindingConfigurationElement binding in bindings[bindingExtension.Name].ConfiguredBindings)

        {

            Console.WriteLine("{0} : {1} : {2}",

                bindingExtension.Name,

                bindings[bindingExtension.Name].BindingType.FullName,

                binding.Name);

        }

    }

}

 

Enumerate all of the configured endpoints exposed by a service

The scenario I hear most described around this scenario involves a client application that wants to fill a selector control to dynamically chose how to communicate with a given service. This often starts as a request for enumerating all of the available bindings, thus my initial question of "Why?". Here, "enumerating all of the available bindings" really means all of the exposed service endpoints since a binding only makes up one third of an endpoint and a service most likely will not support an endpoint for every binding and not limit itself to a single endpoint per binding.

 

Again, the solution here becomes enumerating elements of a specific configuration collection and once you know what collection to enumerate the solution becomes straightforward. Inside the System.ServiceModel configuration section group exists the Services section. This section contains a collection of Service elements, each of which contains a collection of endpoints. These endpoints contain the desired information of address, binding, and contract.

<configuration>

  <system.serviceModel>

    <services>

      <service name="myService">

        <endpoint name="endpoint1" address="address1" binding="basicHttpBinding" contract="contract1" />

        <endpoint name="endpoint2" address="address2" binding="netTcpBinding" contract="contract2" />

        <endpoint name="endpoint3" address="address3" binding="netNamedPipeBinding" contract="contract3" />

    </service>

    </services>

  </system.serviceModel>

</configuration>

 

The solution here actually does include one small difference from the other scenarios in this post: the application.config file that contains the information belongs to the service and not to my app. Thankfully, System.Configuration includes a mechanism for opening an application.config file for a different application assuming you have access to the physical application.config file (and know the location). For the code snippet below, I have expressed that as the method's parameter serviceConfigFile. This opens the service's application.config file and enumerates the service endpoints configured within.

 

Here is a quick bit of code that accomplishes this task and displays the information to the console:

static void EnumerateAvailableServiceEndpoints(string serviceConfigFile)

{

    ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();

    fileMap.ExeConfigFilename = serviceConfigFile;

    Configuration appConfig = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);

    ServiceModelSectionGroup serviceModel = ServiceModelSectionGroup.GetSectionGroup(appConfig);

    Console.WriteLine("Service Name: Configuration Name : Address : Binding : Contract");

    foreach (ServiceElement service in serviceModel.Services.Services)

    {

        foreach (ServiceEndpointElement endpoint in service.Endpoints)

        {

            Console.WriteLine("{0} : {1} : {2} : {3} : {4}",

                service.Name,

                endpoint.Name,

              endpoint.Address,

                endpoint.Binding,

                endpoint.Contract);

        }

    }

}

 

Enumerate all of the configured client endpoints available to my app

The scenario I hear most described around this scenario involves a client application that wants to fill a selector control to dynamically chose how to communicate with a given service and even with which service to communicate. As above, this often starts as a request for enumerating all of the available bindings, thus my initial question of "Why?". Here, "enumerating all of the available bindings" really means all of the exposed client endpoints since a binding only makes up one third of an endpoint and clients most likely will not support an endpoint for every binding and not limit themselves to a single endpoint per binding.

 

Again, the solution here becomes enumerating elements of a specific configuration collection and once you know what collection to enumerate the solution becomes straightforward. Inside the System.ServiceModel configuration section group exists the Client section, which contains a collection of endpoints.

<configuration>

  <system.serviceModel>

    <client>

      <endpoint name="endpoint1" address="address1" binding="basicHttpBinding" contract="contract1" />

      <endpoint name="endpoint2" address="address2" binding="netTcpBinding" contract="contract2" />

      <endpoint name="endpoint3" address="address3" binding="netNamedPipeBinding" contract="contract3" />

    </client>

  </system.serviceModel>

</configuration>

 

Since the client application wants to enumerate the configured endpoints available to itself, we again return to the simpler solution of opening the application's own application.config file.

 

Here is a quick bit of code that accomplishes this task and displays the information to the console:

static void EnumerateAvailableClientEndpoints()

{

    Configuration appConfig = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);

    ServiceModelSectionGroup serviceModel = ServiceModelSectionGroup.GetSectionGroup(appConfig);

    Console.WriteLine("Configuration Name : Address : Binding : Contract");

    foreach (ChannelEndpointElement endpoint in serviceModel.Client.Endpoints)

    {

        Console.WriteLine("{0} : {1} : {2} : {3}",

            endpoint.Name,

            endpoint.Address,

            endpoint.Binding,

            endpoint.Contract);

    }

}

 

I hope this sheds some light on the various methods of enumerating bindings available to an application using the WCF configuration system.

 

Mark Gabarra

This posting is provided "AS IS" with no warranties, and confers no rights. Use of included script samples are subject to the terms specified at https://www.microsoft.com/info/cpyright.htm