WCF Services with .NET 4.0

By | January 5, 2011

In .NET 4.0, initial ramp-up with WCF services has been greatly simplified. This bare bones guide gets you up and running with the basics in about 10 minutes, without any of the onerous XML file hacking that WCF has been known for.

This post assumes you are working with Visual Studio 2010 and the 4.0 version of the .NET framework.

Starting Up – The Host

Our simple example will consist of two console applications, a host and a client. Our service will be a string reversal service. We will start with the host.

We start with a new console application, adding a reference to System.ServiceModel.

addReference

Next we define our service interface. Note the attributes that we decorate the interface and method with.

using System;
using System.ServiceModel;

namespace WCFWork
{
    [ServiceContract]
    public interface IReverserService
    {
        [OperationContract]
        string Reverse(string input);
    }
}

We need the System.ServiceModel namespace for the attributes that tell the framework that this is a service contract. We then decorate the class with the ServiceContract attribute, and the method with the OperationContract attribute.

Next up is our implementation.

using System;

namespace WCFWork
{
    public class ReverserService : IReverserService
    {
        public string Reverse(string input)
        {
            char[] i = input.ToCharArray();
            Array.Reverse(i);
            return new String(i);
        }
    }
}

Nothing fancy going on here, just a simple implementation of string reversal.

Finally, we modify the main method of the console application to host our service.

using System;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace WCFWork
{
    class Program
    {
        static void Main(string[] args)
        {
            using (ServiceHost host = new ServiceHost(
                typeof(ReverserService), 
                new Uri("net.tcp://localhost:9000")))
            {
                host.Description.Behaviors.Add(new ServiceMetadataBehavior());
                host.AddServiceEndpoint(
                    typeof(IMetadataExchange),
                    MetadataExchangeBindings.CreateMexTcpBinding(),
                    "mex");
                host.AddServiceEndpoint(
                    typeof(IReverserService), 
                    new NetTcpBinding(), 
                    "net.tcp://localhost:9000/ReverserService");
                host.Open();
                Console.WriteLine("press enter to stop service...");
                Console.ReadLine();

                host.Close();
            }
        }
    }
}

Things get a lot more interesting here. Note that we could reduce the code if we added some configuration to our app.config; given that one of the goals of this post was to demonstrate a simple WCF service scenario without XML fun, we are eschewing that option.

We start by declaring a new ServiceHost for our service. This is the class that will be listening for incoming requests. We want our service to be functional but also descriptive; this is what the next 2 lines do for us. We are enabling metadata exchange by adding the corresponding behavior and endpoint. The endpoint addition required inclusion of the System.ServiceModel.Description namespace so that we could specify the type of binding we wanted for our metadata endpoint.

The next line adds our actual service endpoint – this is what clients will use for to reverse their strings. Next, we start our host and await client calls until someone presses a key. Pretty simple, and again, zero configuration. Building and running our solution produces the grand display of functionality below.

serviceHostRunning

 

The Client

Leaving our host running, we start up another instance of Visual Studio 2010 and begin a new console application. We now add a new service reference as below.

addServiceReference

Note the URI that we typed in the address box. This is using the metadata exchange endpoint that we configured in the host, and makes it terribly straightforward to both get a reference to our service and to write the code that will use the service.

using System;

namespace WCFWorkClient
{
    class Program
    {
        static void Main(string[] args)
        {
            ReverserService.ReverserServiceClient reverser =
                new ReverserService.ReverserServiceClient();

            string reversed = reverser.Reverse("hi there how are you");

            Console.WriteLine(reversed);
            Console.ReadLine();

            reverser.Close();
        }
    }
}

Adding the service reference the way we did instructed Visual Studio 2010 to pull down the service definition and generate code based on this service definition. It’s this generated code that allows us to write the first two lines in the main method as cleanly as we did; we simply instantiate the generated class and call the method. The only other (very important) use of the generated class is the last line in the method where we close out the connection. Running our test client (again, ensure that the host is still running) gives us the below.

finalOutput

A Tiny Fib

I started out by saying that we were going to implement this example without any XML file tinkering. While the host was able to get away without having any XML configuration whatsoever, the client was not so lucky. While adding the service reference using the Visual Studio 2010 IDE made our code very clean, it did modify our app.config in a not-so-clean way…

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <bindings>
            <netTcpBinding>
                <binding name="NetTcpBinding_IReverserService" closeTimeout="00:01:00"
                    openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
                    transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions"
                    hostNameComparisonMode="StrongWildcard" listenBacklog="10"
                    maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
                    maxReceivedMessageSize="65536">
                    <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                    <reliableSession ordered="true" inactivityTimeout="00:10:00"
                        enabled="false" />
                    <security mode="Transport">
                        <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
                        <message clientCredentialType="Windows" />
                    </security>
                </binding>
            </netTcpBinding>
        </bindings>
        <client>
            <endpoint address="net.tcp://localhost:9000/ReverserService"
                binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IReverserService"
                contract="ReverserService.IReverserService" name="NetTcpBinding_IReverserService">
                <identity>
                    <userPrincipalName value="" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>
</configuration>

DIsgusting, but there are ways to get around this, and we will explore those in future posts. Note that the userPrincipalName node will actually be non-empty, I simply cleared it out because I don’t trust all of you enough to share my deep dark secrets.

Next Steps

There are scads of options when it comes to WCF services: endpoints, bindings, consistency models, tracing, profiling, discoverability, etc. It can be pretty daunting trying to learn about it all. Always remember to solve the problem at hand, and not just be seduced by the allure of shiny new toys. In future posts we will try to chip away at some of the complexity of WCF services so as to provide a slightly better context when trying to decide what, where, and when to apply this technology.