Udostępnij za pośrednictwem


So What Is A WCF Configuration Extension Anyways?

I apologize in advance for the rushed tempo of this discussion. Unfortunately, I still struggle with finding (or in some cases creating) time dedicated for writing blog posts; however, I wanted to make sure and get the bulk of this content posted this week. I briefly struggled with the trade off of posting less polished content quickly with more polished content at less regular intervals. Feel free to let me know if you would rather me wait until the content reaches a more coherent quality level.

My previous posts focused on how to enumerate the three Windows Communication Foundation (WCF) configuration extension points: bindings, behaviors, and binding elements. Normally, I would like to actually introduce a topic in a general sense before diving into specific coding examples; however, those specific coding questions provoked the very existence of this blog. Thus the slightly backward approach at this topic. So now that I have described in detail how, and in some cases why, you enumerate the various configuration extensions in WCF configuration, allow me to describe what are WCF configuration extension points, why we have them, and why we chose these three.

What are these things?

Simply put, the WCF configuration extension points allow developers external to the WCF product team extend specific points of the WCF configuration schema and object model. The <extensions> section in the WCF configuration schema exists to allow developers to create their own configurable objects that plug into the WCF configuration schema as if they existed as part of the WCF product. Allow me to give a specific example.

The WCF product will ship with a set of configurable transport elements that can be consumed by a custom binding. To configure a custom binding that uses the tcp transport, you would include the following block in your application’s configuration file:

<configuration>

  <system.serviceModel>

    <bindings>

      <customBinding>

        <binding name="myBinding">

          <tcpTransport/>

        </binding>

      </customBinding>

    </bindings>

  </system.serviceModel>

</configuration>

Instead of trying to create every possible transport at the time WCF goes out the door, we decided to create a mechanism to allow developers to create their own custom transports. Further, through this extension mechanism, we allow developers to expose their transports through the WCF configuration system. Ideally, we would allow a developer to create “customTransport” and attach it to a custom binding with the following configuration:

<configuration>

  <system.serviceModel>

    <bindings>

      <customBinding>

        <binding name="myBinding">

          <customTransport/>

        </binding>

      </customBinding>

    </bindings>

  </system.serviceModel>

</configuration>

Why have them?

After all, the WCF configuration system extends the .NET 2.0 System.Configuration system. Why create an additional extension mechanism for the WCF configuration portion? Simply put, the System.Configuration extension points did not cover this particular scenario. System.Configuration allows developers to plug in custom ConfigurationSectionGroup and ConfigurationSection objects. ConfigurationSectionGroups can only contain ConfigurationSection objects and cannot include any attributes or configuration data. In other words, section groups exist to define hierarchy and scope only. ConfigurationSections, on the other hand, can contain attributes as well as child nodes of type ConfigurationElement and/or ConfigurationElementCollection. They cannot, however, contain other ConfigurationSections. The WCF configuration system required the ability to plug in custom ConfigurationElement objects.

Because we cannot simply take a element name (“customTransport” in the previous case) and “auto magically” determine how to deserialize the associated XML, we created a registration point that allows developers to register a ConfigurationElement object that knows how to deserialize the given XML with an element name. This results in the actual configuration looking like:

<configuration>

  <system.serviceModel>

    <extensions>

      <bindingElementExtensions>

        <add name="customTransport" type="[SomeNamespace].[SomeConfigurationElementType], [SomeAssembly]"/>

      </bindingElementExtensions>

    </extensions>

    <bindings>

      <customBinding>

        <binding name="myBinding">

          <customTransport/>

        </binding>

      </customBinding>

    </bindings>

  </system.serviceModel>

</configuration>

The <extensions> section provides a centralized location for this registration of XML element name to ConfigurationElement object required for creating a relatively open extensibility point to the WCF configuration system. Each configuration extensibility point connects to one of three collections within this section: behaviorExtensions, bindingElementExtensions, and bindingExtensions.

Why these three and only these three?

Those of you who dive deeply into the WCF configuration system may complain that the WCF configuration system contains more extensibility points than just these three. Yes, a few more extensibility points exists; however, for the scope of this discussion allow me to limit “configuration extensibility points” to mean the extensibility points contained in the <extensions> section of the WCF configuration schema, of which only three exist: behavior extensions, binding element extensions, and binding extensions. Looking at the WCF object model, and ignoring the configuration surface for the moment, five basic extensibility points jump out, at least to me: ServiceHost, IEndpointBehavior, IServiceBehavior, BindingElement, and Binding. These objects make up the basic building blocks of WCF services and communication channels. When looking to include this extensibility in the WCF configuration system, the last four objects all have very custom configuration surfaces for each distinct implementation. The ServiceHost configuration surface exposes itself in a very generic manner, and thus does not need its own configuration extension. The IEndpointBehavior and IServiceBehavior interfaces allow for a single object to fit both categories, thus requiring a single configuration object to service both extensions. This leads us to requiring three configuration extension points.

I hope this helps plug in some of the background information holes regarding the WCF configuration extensions that my previous “How To” posts may have left open.

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
    June 08, 2009
    PingBack from http://toenailfungusite.info/story.php?id=5938

  • Anonymous
    July 06, 2009
    I have added a new behavior extension which I use as a xml-rpc endpoint. The problem I have is that all requests go though it and not only the requests that are specifically addressed to that endpoint. This has broken my other endpoint, ie soap. Any suggestions? Thanks

  • Anonymous
    March 08, 2010
    Niko - 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. If I were to hazzard a guess (and this in only a guess and should in no way be construed as a Microsoft answer since I no longer work for Microsoft), I would say that your new behavior extension is not properly passing requests that it should not handle.  If I remember correctly (and it has been a number of years), each behavior on an endpoint receives the request in its turn.  If you are not careful you can affect the request for behaviors deeper down the stack.  It sounds to me like you are trying to use the behavior extension model to provide two different processing models on a single endpoint based on the request.  You need to make sure if this behavior is not supposed to handle a request it allows it to flow down the behavior stack.