It is .NET time again! As I have landed a job as a .NET backend developer in the aviation industry (pun sort of unintended) I will not anymore be working with Django on a daily basis (become a contributor perhaps?). However, I will get my hands onto a large stack comprising varied airport solutions and work with .NET technologies that I never had the opportunity to play around with, both new and old. Setting aside the pains and joys of discovering a massive new stack, it is an opportunity (and also a necessity) for me to quickly get up to speed with all of these new technologies. One of them is good ol’ WCF. So that’s me learning this thing, and trying to transfer this new knowledge to anyone looking for some helpful insights with the Windows Communication Foundation.

The good news: Fortunately, my first steps with WCF are boiling down to a very positive impression of the framework, with the usual pros and cons of other Microsoft toolsets. It is very configurable, which can be a bless and no less of a curse, especially when setting up bindings between services or services and clients; it works wonderfully with Visual Studio, enabling said configuration and ensuring that service-client operations work seamlessly across projects in a Solution… that is, if you use Visual Studio at all. Otherwise, it is safe to assume that a lot of playing around and trial and error can happen. It is (sort of) open source, yes, but it is obviously windows first, with the most immediate hosting options always pointing towards a Microsoft product. I reckon that up to this point there’s nothing unexpected.

However, once accepted the boundaries of the Microsoft stack, WCF offers a very stable and powerful solution for distributed systems. I hope that my brief experience with it and the project and tutorial shared in this article can help you understand and take the most out of this framework, or at least encourage you to just give it a go and see how it works. The goal: having a minimum of experience as a developer, you should be ready to build a simple app by the end of this text. Nonetheless I have created a test project, a tiny calculator app, that you can use to play around. Feel free to get it here:

https://github.com/DazEdword/WcfExample

Now let’s take a quick look at the structure of our project:

  • WcfMiniApp is our WCF project, containing our two services (CalcService and CoolService, feel free to completely ignore the latter), the contracts defining them (their interfaces) and config files.
  • ConsoleTestBinding is a console project referencing our WCF services.
  • WcfTests is a test project using NUnit and Nsubstitute, containing unit tests for service and console app, and a helper allowing us to test private and static methods*.

*I know that many excellent programmers argue that the whole point of unit testing is to test public interfaces, but I appreciate the granularity and robustness that some private method testing provides, and anyway it’s frequently worse to just change visibility from private to public just for the sake of testing. There is no perfect solution, and there will not ever be. Welcome to Test Driven Development, hope you will enjoy your time with us**.

**Ha, guaranteed sometimes you will not.

What’s WCF

Windows Communication Foundation (WCF) is a runtime and set of APIs working under the .NET framework for building service-oriented applications. Using WCF, you can send data as asynchronous messages from one service endpoint to another.

Originally released in 2005 WCF is not precisely a groundbreaking, ultra-modern technology, but it is still in development and getting support for Microsoft’s latest web solutions within the .NET ecosystem, such as ASP.NET Core (and in fact, you can see all of that code by yourself in this GitHub repo here).

Before taking a deep dive in our project, WCF philosophy and features can be summarised in this list of bullet points:

  • Service oriented: WCF services metadata are complient with standards such as WDSL,among others. read about Service-Oriented architecture here.
  • Interoperable: WCF is designed to allow communication with other web standards and technologies.
  • Message flexibility: use the request/response pattern that we all know and love, or whatever suits your requirements
  • Data contract: separate your service implementation (class) from its definition (normally, interace), and leave WCF to auto-generate clients that work with your data.
  • Transport flexibility: messages can be sent on any protocol or encoding (usually SOAP/HTTP or REST/HTTP, using XML or JSON).
  • Extensibility: create simple apps easily or extend it as large systems evolve.

WCF Workflow

Or how we will build our app:

  1. Define the service contract. A service contract specifies the signature of a service, the data it exchanges, and other contractually required data.
  2. Implement the contract via service class. To implement a service contract, create a class that implements the contract and specify custom behaviors that the runtime should have. For more information, see Implementing Service Contracts.
  3. Configure the service by specifying endpoints and other behaviour information.
  4. Host the service. For more information, see Hosting Services.
  5. Build a client application.

Luckily, we do have a test project to follow this workflow step by step. Of course, we’ll need a Visual Studio solution, and I’ll assume you are comfortable enough with the software as for to know how to create them. If you have installed WCF with your Visual Studio installation, you should be able to create a WCF app project right off the bat.


1- Define the service contract

That’s an easy one. We simply create a good old interface, defining the operation that our service needs to perform. Our silly calculator will only do additions and subtractions of two integers, either directly or through a Process method that will handle requests. Notice the decorators over the service and operations, including an async one.

using System.ServiceModel;
using System.Threading.Tasks;

namespace WcfTestApp
{
    [ServiceContract]
    public interface ICalcService
    {
        [OperationContract]
        int Add(int a, int b);

        [OperationContract(AsyncPattern = true)]
        Task<int> AddAsyncTest(int a, int b);

        [OperationContract]
        int Subtract(int a, int b);

        [OperationContract]
        Response Process(Request request);
    }
}

2- Implement the contract

In Visual Studio is as simple as adding a new item of type WCF Service.

namespace WcfTestApp {
    public class CalcService : ICalcService {

        public Response Process(Request request) {
            int? result;
            bool success;

            try {
                switch (request.operation) {
                    case "add":
                        result = Add(request.a, request.b);
                        break;

                    case "subtract":
                        result = Subtract(request.a, request.b);
                        break;

                    default:
                        result = null;
                        break;
                }

                success = true;
            } catch (System.Exception) {
                result = null;
                success = false;
            }

            return new Response() {
                result = result,
                success = success
            };
        }

        public int Add(int a, int b) {
            return a + b;
        }
}

It is worth highlighting that our request and response objects are just extremely simple classes that we have created ad hoc to handle the variables that we need to send back and forth across our server and client, and they can be as simple or complicated as you want. For our example:

public class Request {
    public string operation;
    public int a;
    public int b;
}

public class Response {
    public bool success;
    public int? result;
}

Note that WCF can handle any class, but ideally we would be defining them using the [DataContract] and [DataMember] decorators in order to explicitly enforce the data contract that we decide our service to stick to (and offering us some extra capabilities), in which case each class would be as shown in this example:

[DataContract]
public class Response
{
    [DataMember]
    public bool success;
    [DataMember]
    public int? result;
}

3 and 4- Configuration and hosting

As you can probably guess, here’s when things start to get tricky. It is beyond the scope of this beginner tutorial to delve into the details of configuration, so we will stick to the simplicity of our project, and take advantage of all the help that Visual Studio can provide. As we are not going to deploy our app, hosting is out of the question, and we’ll just let IIS take care of hosting it in our local environment. As for the configuration, we only need to worry about binding.

Bindings are objects that specify the communication details required to connect to an endpoint. From Visual Studio, binding files can be auto-generated using its UI. Our client is going to be a simple console app that will connect to our service. In the Solution, create the console app project. Then in Connected Services, right-click → Add Service Reference. Either click Discover to auto-detect services across the solution, or add the address to the service. Click OK.

From this point, our service binding should be automatically generated for us, and it will look like this:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
    </startup>
    <system.serviceModel>
        <bindings>
            <basicHttpBinding>
                <binding name="BasicHttpBinding_ICalcService" />
            </basicHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:56890/CalcService.svc" binding="basicHttpBinding"
                bindingConfiguration="BasicHttpBinding_ICalcService" contract="CalcServiceReference.ICalcService"
                name="BasicHttpBinding_ICalcService" />
        </client>
    </system.serviceModel>
</configuration>

Bear in mind that if a change is made on the service, we’ll need to update our references manually by right-clicking the connected service → Update Service Reference.

And that concludes configuration! We can create whatever the client we need to interact with our service, as you can see in this console app example:

using System;

namespace ConsoleTestBinding {
    public class CalcConsoleClient {
        public static string[] availableOperations = { "add", "subtract" };
        public static IGetInput Input = new Input();
        public static IPrintOutput Output = new Output();

        public static void Main(string[] args) {
            using (var client = new CalcServiceReference.CalcServiceClient()) {
                Console.WriteLine("Welcome to the WCF calculator. Please make sure to type your input and press enter when prompted.");
                Console.WriteLine(String.Format("Let's do some simple math. The available operations are: {0}", String.Join(", ", availableOperations)));
                Console.WriteLine("What operation would you like the app to perform?");

                string operation = GetUserOperationInput();
                Console.WriteLine("First digit?");

                int a = GetUserNumericalInput();

                Console.WriteLine("Second digit?");
                int b = GetUserNumericalInput();

                Console.WriteLine("Sending request to server...");
                var req = new CalcServiceReference.Request() {
                    operation = operation,
                    a = a,
                    b = b
                };

                var response = client.Process(req);

                if (response.success == true) {
                    Console.WriteLine(String.Format("Your result: {0}", response.result));
                } else {
                    Console.WriteLine("Operation failed.");
                }

                Console.ReadKey();
            }
        }

        static int GetUserNumericalInput() {
            int value;

            while (!int.TryParse(Input.GetUserInput(), out value)) {
                Output.PrintUserOutput("Please Enter a valid numerical value!");
            }

            return value;
        }

        static string GetUserOperationInput() {
            string userInput = null;

            bool valid = false;

            while (!valid) {
                userInput = Input.GetUserInput();

                switch (userInput) {
                    case "add":
                        valid = true;
                        break;
                    case "subtract":
                        valid = true;
                        break;
                    default:
                        Output.PrintUserOutput("Please Enter a valid operation!");
                        break;
                }
            }

            return userInput;
        }
    }

    /// <summary>
    /// Abstracting input and output for better testability. In practice, we are just using 
    /// Console.ReadLine and Console.WriteLine.
    /// </summary>
    public class Input : IGetInput {
        public string GetUserInput() {
            return Console.ReadLine();
        }
    }

    public class Output : IPrintOutput {
        public void PrintUserOutput(string message) {
            Console.WriteLine(message);
        }
    }

    public interface IGetInput {
        string GetUserInput();
    }

    public interface IPrintOutput {
        void PrintUserOutput(string message);
    }
}

WCF Testability

As it happens with other aspects of WCF and you have probably noticed, the closer we stay to Visual Studio the better WCF is going to work for us, and that extends to unit testing as well. Not only Visual Studio offers the integrated test runner to seamlessly run and debug our tests, it also offers a simple client interface to test our service directly, and also allows us to auto-generate a variety of clients that adapt to our service, taking care of automatically running the service once we boot our client.

Let us start with Visual Studio’s test client. Right-click service to test → Set as Start Page → click Start Debugging. A window like this should appear:

On this WCF Test Client window, double-click method and change params (if any) → click “Invoke” to run. New services can be added to the test client by using File → Add Service. That’s it! Your service is alive and you are communicating with it. That was our first option.

But what about our console app? Surely the binding will work here as well. Set up ConsoleTestBinding project a startup project and click Start in Visual Studio. Follow the instructions on screen, add your input when prompted and just press enter to progress through the application. That’s our second client right there, successfully using our WFC service, that is initialised via binding with the console project.

We can even start the service on its own, and use third-party software to call its endpoint. Let’s try SOAPUI, which you can download here. First, set up our service project as startup project in Visual Studio again and start it. File → New SOAP Project → Add endpoint to our service (that you can find on your service config, or even showing automagically in VS’s test client) + ?wsdl (e.g. http://localhost:56890/CalcService.svc?wsdl) → double-click method to test → modify params (if any) → click play. That’s our real SOAP request, for us to see.

Of course we can do similarly for REST requests, but the configuration will differ.

And last but not least, we have automated testing. Directly testing code from a service is absolutely trivial: instance the class containing the service functionality, interact with it via your desired test framework and assert with your tools of choice. For a TDD fan such as myself this is a must, and luckily both MSTest and NUnit have worked marvelously for me; consider our service CalcService, and our test file CalcServiceTests in a separate unit test project. Note that in order for Visual Studio to detect and the project’s NUnit tests you’ll need to install NUnit 3 Test Adapter via extensions.

As stated, we can just instance our service class, and call the Process method with our arbitrary request object, then assert our returned response (also arbitrary and user-defined).

using NUnit.Framework;
using NSubstitute;
using WcfTestApp;

namespace CalcServiceTests {
    [TestFixture]
    public class CalcServiceTests {

        public CalcService service;

        [SetUp]
        public void SetUp() {
            service = new CalcService();
        }

        [Test]
        public void ProcessCallsAddMethodWhenRequestOperationIsAdd() {
            // Arrange

            var MockRequest = new WcfTestApp.Request() {
                operation = "add",
                a = 1,
                b = 1
            };

            // Act
            var response = service.Process(MockRequest);

            // Assert
            Assert.IsTrue(response.success);
            Assert.AreEqual(response.result, 2);
        }
    }
}

And we are done! We have a nice WCF service running, a console application to test it, and tests covering both of them. Hope this article has helped, feel free to ask or share anything on the comments.

Some resources

  1. MSDN knowledge base.
  2. Official Microsoft WCF tutorial.
  3. Basic WCF Programming.
  4. Fundamentals of WCF Security.
  5. Hosting WCF service in IIS.
  6. WCF example project.