In the attempt to master the basic topics and extensibility points of WCF, we are going to look to WCF Custom Bindings and their possibilities.
For certain scenario’s, our company would like to use a netHttpBinding, which is not a default binding. Thus our netHttpBinding will be a custom binding which uses BinaryEncoding and HttpTransport, in contrast to the default http bindings which use TextMessageEncoding and HttpTransport. Binary encoding is a proprietary .NET protocol, but in our cases this is not an issue as we don’t have to be interopable. We know the clients are .NET clients, somewhere around the globe and to gain performance at the encoding, we want to use a custom httpbinding that uses binary encoding.
This might not be a ideal scenario, but it is good enough to run past the basic principles.
1. Custom binding by configuration:
Our solutions look as following:
We have 2 projects in our solution:
“WCF.Binding.Custom.client”: Client console application, used to mimic a client
“WCF.Binding.Custom.Service”: WCF Service Application, with 1 WCF service called “SaasService”
Our service contract:
Our service implementation:
Our web.config of our WCF service application:
Note we defined a customBinding at our <bindings> section and called it “netHttpBinding”. The binding uses binaryMessageEncoding and httpTransport. Our endpoint has customBinding set as binding, while the bindingConfiguration points to “netHttpBinding”, which is our name of the custom binding configuration.
You can also configure other things on the custom binding, like transactionFlow, security and so forth. At the lowest level the Transport should be defined and the next one to define is the encoding that will be used. Both these settings are required for any custom binding. The other settings like reliableSession, transactionFlow, security, … are possible, but not required and depend on what binding you want to create.
We host the WCF service by our local IIS (Properties – Tab Web – Create Virtual Directory):
Our local url to our WCF service is : http://localhost/WCF.Binding.Custom.Service/SaasService.svc
When adding a service reference to our client to our localhost url of our IIS hosted service, our app.config looks like this:
It reads the custom binding from the exposed WSDL and appends the default values to the configuration.
Our client console application code:
And when executing the client console application:
2. What about a reusable Custom Binding that can be used over multiple projects, like the default bindings ?
We created a custom binding that fits some of our custom scenario’s and we configured this custom binding by configuration. But what if I have to use this custom binding over another 10 projects ? Do I have to copy this custom binding configuration to each ? What if for some reason the custom binding has to add a bindingElement, do you have to change the other 9 projects aswell then ?
There is also a possibility to create a custom binding that behaves the same way as the default bindings. A binding that you can select, just as you can chose basicHttpBinding and the custom binding is configurable by configuration, just as the other default bindings are. We create a class library that holds this custom binding and we share the class library between the projects. Each project can still configure some binding settings, like maxMessageSize etc in the configuration, but the build of the custom binding is identical for each project.
We want to create our custom binding NetHttpBinding again, but make it reusable and configurable by configuration, just like any other default binding.
We start by creating a class library for our NetHttpBinding:
Make sure you already add the System.ServiceModel reference to the newly created class library.
To create a reusable and configurable custom binding, there are a few steps you have to go through:
1. Create your custom binding with the abstract class Binding
We will start by creating a new class called “NetHttpBinding”, which will be our custom binding.
Our solution looks like this:
Our NetHttpBinding will inherit from the abstract class System.ServiceModel.Channels.Binding:
Implement the abstract class from the Binding class and this is what we get:
So we must override 2 methods of our Binding class:
The createBindingElements has to return a bindingElementCollection that holds all the bindingElements for the custom binding. This is the same as what we did in our web.config configuration for our custom binding, but now it is set by code. The second method we have to override is the “Scheme“ method, which returns the used scheme for the binding. In our case, this is a very simple binding, that only allows http transport, so we return “http” hardcoded. In a real scenario, you will most likely support multiple protocols like http + https, so in that case you would have to save your transport element in your NetHttpBinding class and get the scheme from the transport element that has been chosen by the configuration set on the binding.
This binding is now usable by code, so you can create a netHttpBinding and configure it by code. (Though you have to make NetHttpBinding class public then, as it is currently defined internal)
To make the binding configurable by configuration in configuration file, there are two more steps to be taken:
2. Create a Custom BindingElement with the Configuration.StandardBindingElement
Next step in line is to create a BindingElement for our NetHttpBinding, by inheriting from System.ServiceModel.Configuration.StandardBindingElement. As you notice we are working with System.ServiceModel.Configuration, which is to make our NetHttpBinding usable and configurable by configuration file, just like the other default bindings.
You will need to add a reference to System.Configuration.
We create a class called “NetHttpBindingElement”, which inherits from StandardBindingElement:
There are 2 methods that have to be overridden, the BindingElementType and the OnApplyConfiguration method.
BindingElementType: Returns the type of the binding, which in our case is the NetHttpBinding (:Binding) type
OnApplyConfiguration: Set the binding settings you want to use by default for the NetHttpBinding
3. Create a custom BindingCollectionElement with the Configuration.StandardBindingCollectionElement
To finalize our custom NetHttpBinding to be configurable by configuration, we need to create a class that sets the StandardBindingCollectionElement. The class we create that inherits from the StandardBindingCollectionElement is also the class we will need to point to when we register the extension in our configuration.
We will create a class called “NetHttpBindingCollectionElement”: (click to enlarge)
We have to pass the binding and the bindingconfiguration to the StandardBindingCollectionElement<x,y>. Our binding is the “NetHttpBinding” and our binding configuration is the “NetHttpBindingElement”
The class itself is empty, only the definition of the StandardBindingCollectionElement with what binding and what binding configuration to use is what is important.
This is the class we will reference to for the registration of the binding extension.
Our solution looks like this now:
4. Use the custom binding NetHttpBinding at our service
We will start by adding a reference to our NetHttpBinding class library at our WCF Service Application.
Next we adapt the web.config to register our custom NetHttpBinding and our endpoint to use this NetHttpBinding:
The same as with behaviors, we register extensions at the <extensions> node. Since we created a binding, we use <bindingExtensions> and register the custom binding we created. We call it netHttpBinding and the type is the Full Namespace+name of the StandardBindingCollectionElement, in our case “NetHttpBinding.NetHpttBindingCollectionElement” and the second parameter is the name of the library.
We registered our custom binding as “netHttpBinding” at our extensions, so we can set the binding of our endpoint to netHttpBinding.
To test our new custom binding, update the service reference at the client. The app.config looks as following:
To our client this a custom binding, which it also is.
When running the client console application:
5. What about adding configuration elements to our custom binding
One of the uses of StandardBindingElement is for configuration. If we want to add custom properties to our custom binding and be able to set these properties on our custom binding by configuration, we need to add some extra code to our NetHttpBindingElement, which inherits from the StandardBindingElement.
Our NetHttpBindingElement looks as following:
We created a ConfigurationProperty called “useBinaryEncoding” of which the default value is true.
We also overridden the Properties property of the StandardBindingElement, and we add “useBinaryEncoding” to the possible ConfigurationProperties of our binding for configuration. Note this is for configuration.
We added some code to the OnApplyConfiguration(Binding binding), which gets the netHttpBinding and sets the custom property on the NetHttpBinding to the value of our configuration property of useBinaryEncoding.
Finally we override the InitializeFrom method which initializes the from the binding.
Our NetHttpBinding, which inherits from System.ServiceModel.Channels.Binding, looks like this:
We added a property, which holds the same name as the property we defined for our Configuration property, named “UseBinaryEncoding”.
At our CreateBindingElements() method we changed so that we check the UseBinaryEncoding property value, before we decided what message encoding we will use for our custom binding.
If the UseBinaryEncoding is set to true (the default value) we will use the BinaryMessageEncodingBindingElement. If we chose to set the “useBinaryEncoding” to false in the configuration, a MtomMessageEncodingBindingElement will be used.
Make sure to rebuild the class library NetHttpBinding if you want to use the new changes for the service.
Let’s adapt our service configuration to use our new configuration setting:
As you can see, we added a binding configuration for the “netHttpBinding” which sets the useBinaryEncoding to true. At our endpoint we reference to the bindingConfiguration we created for the NetHttpBinding.
If you now build the service and visit the local url, you should get the default WCF service screen. If you misconfigured any configuration property, you’ll get an error.
At our client console application, update the service reference. The app.config should look like this:
This looks identical to our custom service without the useBinaryEncoding setting, which it also should.
If we do set the value of “useBinaryEncoding” to false in our service configuration, the Mtom message encoder should be used:
If we update our service reference again at the client console application, our app.config looks as following:
You’ll notice our custom binding has changed to a wsHttpBinding with messageEncoding “Mtom”. The reason for this is that HttpTransport + MtomMessageEncoding falls within the possibilities of the wsHttpBinding, so the client generates a wsHttpBinding, which will have the same channels as our custom channel, so they will be able to communicate. In theory it was kind of a bad example of mine, but it still proves the point of configuration settings on the custom binding. Our HttpTransport + BinaryEncoding does not fall within the range of any possible default binding, so a custom binding gets generated then.
Our default bindings are just also a set of bindingElements. The bindingElementCollections that were most used, the grouped as the default bindings and gave them a name.
If we run our client console application with the wsHttpBinding configuration and our service which has the netHttpBinding set:
Even though the the service side has a NetHttpBinding and the client side registered for a WsHttpBinding, the service and client are still able of communicating. At runtime, both the bindings create exactly the same binding channels (an HttpTransport and a MtomMessageEncoding binding element), thus they will be able to communicate since they channel will be identical for both.
Any suggestions, remarks or improvements are always welcome.
If you found this information useful, make sure to support me by leaving a comment.
Cheers and have fun,