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
Comments
Anonymous
May 08, 2006
As a follow up to my previous posts “Is there an easy way to enumerate the bindings listed in configuration?”...Anonymous
May 10, 2006
As a follow up to my previous post “Is there an easy way to enumerate the bindings listed in configuration?”,...Anonymous
July 30, 2006
I'm working to develop a new SOA infrastructure based on WCF for an
enterprise framework underpinning...Anonymous
September 04, 2007
Mark, this is great for apps having access to their own or another app.config. What is being done for apps that only have an app.config xmldocument in memory? From what I'm reading, they have to parse the xml document themselves having no way to tap into wcf's ability to bind xml to system.servicemodel at run time.Anonymous
September 06, 2007
Can you be a bit more specific about what you are trying to accomplish here? I think there might just be a simple misunderstanding here. My code snippets in my blog utilize the System.Configuration object model (and WCF's configuration extensions). These all operate over, essentially, an in-memory XmlDocument representation of the last parsed merged configuration view for an application. The configuration snippets I include are only for illustrative purposes to connect the configuration object model with the configuration XML representation. Does this make sense? Thanks. MarkG http://blogs.msdn.com/MarkGabarraAnonymous
July 10, 2008
PingBack from http://dekoder.wordpress.com/2008/07/11/enumerate-the-bindings-listed-in-wcf-configuration/Anonymous
July 28, 2008
Mike, This was the most enlightening post I've come across in a while because of its timeliness to my current project. Thank you so much!Anonymous
February 24, 2009
Mike, Do you know how to enumberate the properties within a binding? such as <basicHttpBinding> <binding name="MyService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferSize="6553600" maxBufferPoolSize="52428800" maxReceivedMessageSize="6553600" messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">Anonymous
March 15, 2009
The configuration object that details how binding settings are serialized to / deserialized from the configuration file format should inherit from System.Configuration.ConfigurationElement. This means you should be able to see an ElementInformation property from which you can access a Properties collection. This collection of System.Configuration.PropertyInformation objects should give you all the information you want. This should work for the WCF that shipped with .NET 3.5. I cannot say if this is still valid for versions of WCF built against later .NET revisions. To answer that question you will have to contact current members of the WCF product team. Thanks. MarkAnonymous
April 20, 2009
Why not using BasicHTTPBinding myBinding = new BasicHTTPBinding("basicHTTPBinding_name") It automatically reads and assigns all parametersAnonymous
May 26, 2009
PingBack from http://backyardshed.info/story.php?title=mark-gabarra-s-blog-is-there-an-easy-way-to-enumerate-the-bindingsAnonymous
June 12, 2009
PingBack from http://toenailfungusite.info/story.php?id=5931Anonymous
June 13, 2009
PingBack from http://gardendecordesign.info/story.php?id=5890Anonymous
January 14, 2010
// OpenExeConfiguration fails in IIS !!! // http://www.neovolve.com/post/2009/02/19/ConfigurationManagerOpenExeConfiguration-fails-in-IIS.aspx more solutions ??Anonymous
March 08, 2010
ae - I am no longer working at Microsoft on the ILM "2" product and do not have access to the latest information on troubleshooting. I would recommend trying to contact the product group through the official product page. It appears you have found the solution according to your link. As you ellude in your post this is expected behavior. OpenExeConfiguration (as the method name infers) is intended to open an app.config file associated with the current running EXE. This works in the WCF application world for SelfHosted applications. WebHosted applications do not run their own EXE and so this will fail to find the correct file (if it could it would not know how to do the more complex merging of the web hosted app.config hierarchy). Your post's solution of using ConfigurationManager.GetSection() for WebHosted WCF applications is correct as of last I worked with this stuff (it has been a number of years and I no longer work for Microsoft).Anonymous
June 01, 2010
How do you do this if the WCF application was not configured through app.config? In WCF 4 you can have services that work without the sections, or you could configure it in code potentially. How then do you enumerate the endpoints etc