Construct WCF Binding from string (XML)

Jimmy Tønners Blog has an excellent C# snippet on how to convert a bindingconfiguration xml fragment into a Binding. I ported it to VB.Net, and turned it into a function which returns the resulting Binding element.

Imports System.Configuration
Imports System.ServiceModel.Channels
Imports System.ServiceModel.Configuration

''' <summary>Contains methods related to <see cref="Binding">Binding</see> objects which
''' contain all the binding elements that specify the protocols, transports, and message
''' encoders used for communication between clients and services.</summary>
Public Class BindingTool

    ''' <summary>Converts WCF binding definitions from XML, like the kind you see in an
    ''' application's .config file, to a <see cref="Binding">Binding</see> object.
    ''' </summary>
    ''' <param name="customConfig">The XML defining the type of
    ''' <see cref="Binding">Binding</see> to return.</param>
        ''' <returns>A <see cref="Binding">Binding</see> based on the XML supplied.</returns>
    ''' <remarks>Code example courtesy of Jimmy Tønners Blog
    ''' 15 Feb 2011 11:41 AM
    ''' http://blogs.msdn.com/b/jimmytr/archive/2011/02/15/snippet-construct-wcf-binding-from-string-xml.aspx
    ''' </remarks>
    Shared Function BindingFromXML(customConfig As String) As Binding

        Dim configSystem As System.Configuration.Configuration = _
            ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
        Dim bindingSection As BindingsSection = BindingsSection.GetSection(configSystem)
        bindingSection.SectionInformation.SetRawXml( _
            String.Format("<bindings>{0}</bindings>", customConfig))
        Dim bindingCollectionElement As BindingCollectionElement = Nothing
        For Each b As BindingCollectionElement In bindingSection.BindingCollections
            If 0 < b.ConfiguredBindings.Count Then
                bindingCollectionElement = b
                Exit For
            End If
        Next
        Dim newBinding As Binding = DirectCast( _
            bindingCollectionElement.BindingType.Assembly.CreateInstance( _
                bindingCollectionElement.BindingType.FullName), Binding)
        Dim bEleEx As IBindingConfigurationElement = _
            bindingCollectionElement.ConfiguredBindings(0)
        bEleEx.ApplyConfiguration(newBinding)

        Return newBinding
    End Function

End Class

I researched the issue back when we were considering storing all WCF endpoint connection info as XML inside of SQL records so that all 1000+ sites our app would connect to could theoretically have their own private connection info.

We eventually dropped this idea in favor of storing the name of the endpoint connection definition in the SQL record and keeping a limited number of endpoint connection definitions in the application's configuration file. A large part of that reason was that we couldn't figure out how to turn the endpoint XML or the Behavior XML into their respective objects without some poor hack idea like writing them to disk first and then loading them up as an application configuration file.

So in the end we just pass the endpoint configuration name to the WCF client class constructor, and then reassign the Endpoint Address with the URI of the client we want to connect to, but maintain whatever Identity or Address Headers were defined in the application configuration. We also assign the username and password because you can't store those values in the application configuration file and with good reason probably.

        Dim configuration As String = GetConnectionConfigNameForClient()
        Dim username As String = GetConnectionUsernameForClient()
        Dim password As String = GetConnectionPasswordForClient()
        serviceClient = New MediaServiceReference.MediaServiceClient(configuration)
        serviceClient.Endpoint.Address = New EndpointAddress(remoteAddress, _
                                        serviceClient.Endpoint.Address.Identity, _
                                        serviceClient.Endpoint.Address.Headers)

        serviceClient.ClientCredentials.UserName.UserName = username
        serviceClient.ClientCredentials.UserName.Password = password

Even though we solved it that way, I still like Jimmy Tønners solution, so I thought I'd share it.