For the following sections we will utilize following service definition and contract:

[ServiceContract(Name="myservice", Namespace="config.myservice")]
public class IMyServiceContract
{
[OperationContract]
void MyMethod();
}
class MyService : IMyServiceContract
{
public void MyMethod()
{
//omitted
}
}

Administrative Configuration

To administratively configure your endpoints to use in WCF you simply add a system.serviceModel section in your app(exe).config/web.config file like the following example:

<system.serviceModel>
<services>
<service 
name="MyNamespace.MyService">
<endpoint
address = "http://localhost:8080/MyService"
binding = "wsHttpBinding"
contract = "MyNamespace.IMyServiceContract"/>
<endpoint 
address = "net.tcp://localhost:8081/MyService"
binding = "netTcpBinding"
contract = "MyNamespace.IMyServiceContract"/>
</service>
</services>
</system.serviceModel>

You can see the ABC of WCF in the endpoint section. (beeing Address, Binding and Contract or Where, How and What)
It is important that you use fully qualified type names or at service load time an exception is thrown. Again, the binding and address need to be consistent or the service throws an exception on load time. It is also possible to configure several endpoints, as long as the URIs are not identical.

In this config file you can also customize the binding that is used by the endpoint. in the following example we will set the bindingconfiguration to a pre set Bindng, which is configured under the binding section. We set the timeout properties and the messagesize properties.

<system.serviceModel>
<services>
<service 
name="MyNamespace.MyService">
<endpoint 
address = "net.tcp://localhost:8081/MyService"
binding = "netTcpBinding"
bindingConfiguration = "MyTcpBindingConfiguration"
contract = "MyNamespace.IMyServiceContract"/>
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="MyTcpBindingConfiguration"
closeTimeout="00:01:00" 
openTimeout="00:01:00" 
receiveTimeout="00:10:00" 
sendTimeout="00:01:00" 
maxBufferSize="65536" 
maxReceivedMessageSize="65536"/>
</netTcpBinding>
</bindings>
</system.serviceModel>

We named the binding in the section, if we would omit the name, it will count as default binding and its configuration will apply to all bindings that match the exact same type.
There can only be one default binding, so make sure to give them names. Best to name every one and refer explicitly, this avoids confusion.

Programmatic Configuration

Pretty much every configuration you can do administratively, can be done programmatically in an equivalent way.
(actually WCF just parses the config and executes the code itself) [one thing that can only be done administratively, is protocol mapping, which I avoid because it is the exact opposite of explicit definition and will therefore not go into detail about ;-)]

Programmatic configuration has a slightly different feel to it.
To use programmatic configuration you will need to add endpoints to the ServiceHost class, which is defined as follows:

public class ServiceHost : ServiceHostBase
{
public ServiceEndpoint AddServiceEndpoint(Type implementedContract, Binding binding, string address);
// several other ctors and members.
}

(in later posts I am going to demonstrate my serviceHost<TService> class from heitech.WCFUtilXt)

To add an endpoint, you can use either relative or absolut URIs, in the example we simply use the address as a string. We will use the same endpoints as we defined in the administrative example above.

  var host = new ServiceHost(typeof(MyService);
var wsBinding = new WSHttpBinding();
var tcpBinding = new NetTcpBinding();
host.AddServiceEndpoint(typeof(IMyServiceContract), wsBinding, "http://localhost:8080/MyService");
host.AddServiceEndpoint(typeof(IMyServiceContract), tcpBinding, "net.tcp://localhost:8081/MyService");
host.Open(); // Opens the channel see client configuration for more infos on channels

You can also set the Bindingproperties like the administrative way:

  var oneMinute = TimeSpan.FromMinutes(1);
var tenMinutes = TimeSpan.FromMinutes(10);
int msgSize = 65536;
var binding = new NetTcpBinding
{
CloseTimeout = oneMinute,
OpenTimeout = oneMinute,
ReceiveTimeout = tenMinutes,
SendTimeout = oneMinute,
MaxBufferSize = msgSize,
MaxReceivedMessageSize = msgSize
};

This is equivalent to the above bindings section. Yet you can see that it is already more readable than the administrative way (at least from my point of view). I will talk about the advantage of each approach later in this post.

Configure with the Configure() method

There is a third way to configure your Endpoints. Because of the app/web.config file your service is technically bound to the hosting environment (see Hosting your service). To avoid this, WCF offers you to implement a static Configure method in your Service implementation. Note that this method signature has to be matched exactly.

public class MyService : IMyServiceContract
{
public static void Configure(ServiceConfiguration config)
{
var wsBinding = new WSHttpBinding();
var tcpBinding = new NetTcpBinding();
config.AddServiceEndpoint(typeof(IMyServiceContract), wsBinding, "http://localhost:8080/MyService");
config.AddServiceEndpoint(typeof(IMyServiceContract), tcpBinding, "net.tcp://localhost:8081/MyService");
}
}

Here we used the exact same programmatic configuration as above. We could also use the LoadFromConfiguration() method to load the contents of an app.config.

Which to use and mixed approaches

The programmatic version Typesafe and can easily be extended by providing a custom ServiceHost class. On the other hand, you will need to recompile your code for changes to be effective.

The administrative approach gives you more flexibility when you want to refrain from recompiling. But on the downside you have no type safety.

The Configure method helps with being independent from your hosting environment, yet it needs to be replicated in most of the used service implementations of yours.

Also it is possible to mix the ways. E.g. you could name your binding in the config and use this name as a constructor parameter to your Binding that you instantiate in code. Yet, I personally would restrain from mixing both approaches. It makes code harder to understand, harder to spot errors and is not the most explicit way possible. Also a probably valid change in the config would break your code. So you would loose the benefits of each approach, and trade it for the disadvantages of each one.

Summary and Outlook

This was an introduction into service configuration.
For client configuration, see WCF Clientconfiguration . There we will explore how you can generate a Proxy to connect to your service, and use administrative and programmatic configuration to configure the client and proxy.
We will also look at Channels and what they offer for the programmatic model.

To end this view on Configuration I’d like to add my personal opinion on the approaches. I like the programmatic better, because I think it lets me state my intent more clearly. So if I can choose the approach, and given the circumstances it does not matter which one is used I would always prefer the programmatic, not least for the type safety.

In future posts we will look deeper into configurations. This includes ServiceBehavior, transactionbehavior, security and as mentioned client configuration.

Categories: Configuration

0 Comments

Leave a Reply

Avatar placeholder