WCF Windows Service Using TopShelf and ServiceModelEx z

http://lourenco.co.za/blog/2013/08/wcf-windows-service-using-topshelf-and-servicemodelex/

There are two excellent .NET libraries that help us to build enterprise solutions using the Windows Communication Foundation (WCF)TopShelf and ServiceModelEx. These two libraries are responsible for two very different, but integral parts of a windows service:

  • TopShelf enables us to easily debug, install and host a long running process in Windows
  • ServiceModelEx provides functionality to configure how a WCF service behaves and provides its endpoints

This article follows on from my previous article about Service Oriented Architecture. I recommend that if you are just starting out with SOA, you give that a read-through before going through this implementation.

In case you skipped it, we basically want to implement the communication between an application and a service, using WCF:

WCF Windows Service Architecture

What is a Service Interaction?

So what actually makes up a service interaction? There are four necessary elements:

  • A client
  • A service implementation
  • A service host
  • A contract, shared between the client and the service, that describes the interaction

A Little Bit About Contracts

We can think of the contract as an agreement between the client and service as to how they will be communicating.

handshake

Let’s look at a little analogy. People, for example, also have contracts! Consider a normal greeting interaction between two people meeting for the first time:

WCFWindowsServiceGreeting

That makes sense! That is because Braden has an introduction contract (i.e. knows how to respond to a an introduction). In service terms, the contract would be:

  1. João (the client) sends Braden (the service) an introduction request, that contains a greeting, “Hi”, and his name, “João”.
  2. Braden accepts João’s introduction request, and returns an introduction response, that greets João with the same greeting, “Hi”, and in addition, his own name, “Braden”.

Without such a contract in place, you might imagine the following interaction:

WCF Windows Service Greeting No Sense

That makes absolutely no sense! If a server is given a request that it has absolutely no idea what to do with, it will through an error (and that error might as well be gibberish).

Implementation Using TopShelf and ServiceModelEx

Seeing as we are looking at a greeting interaction, why don’t we see if we can implement this as a WCF Windows Service? Let’s get started!

The Visual Studio Solution

In Visual Studio, start with an empty solution. We need to add 4 projects to the solution:

WCF Windows Service Solution Projects

  • Class Library for the contract (WcfService.Contract)
  • A Class Library for the service implementation (WcfService.Service)
  • A Console Application for the client (WcfService.Client)
  • Console Application for the service host (WcfService.WindowsService)

I know what you’re thinking: “Why have so many different projects, there are just two parts to this right?” I like to separate my implementations out so that there is as little code redundancy as possible. The reasons for this separation will (hopefully) become apparent by the end of this article.

Contract

We discussed how contracts describe what is necessary for an interaction to occur earlier. There are three parts to this:

  • Request
  • Action
  • Response

I touched on requests and responses a little earlier. I like to think of these as Data Transfer Objects, or abbreviated to DTOs. These are simple objects that are easily serializable and do not generally reflect the underlying domain objects or database entities. I recommend that you make use of such constructs as they will force you to think carefully about (and therefore limit) the amount of data that as actually sent down the line. The action is simply the method name.

In the contract project, let’s add two classes for our request and response classes – IntroductionRequest:

And IntroductionResponse:

Notice a few things about these classes:

  • The classes are decorated with the DataContract attribute
  • The properties are decorated with the DataMember attribute
  • You will need a reference to the System.Runtime.Serialization assembly that comes with the .NET environment

Let’s add the contract now – add a new interface called IIntroductionService:

Notice a few things about this interface:

  • The interface is decorated with the ServiceContract attribute
  • The method is decorated with the OperationContract attribute
  • You will need a reference to the System.ServiceModel assembly that comes with the .NET environment

Your contract project should now look something like this:

WCF Windows Service Contract

This is a common project that is shared between the client and the service. Remember how we discussed the fact that we don’t want our implementations being released to the whole world in my previous article about Service Oriented Architecture? They don’t have very much to go on, do they?

Service

This is the part of the project where we will implement that actual functionality that our service will provide. The service needs to know what contract it will be fulfilling, so let’s add a reference to the contract project.

Next, add a new class for the service implementation called IntroductionService. We want this class to implement the IIntroductionService in the contract:

Notice a few things about this interface:

  • The class is decorated with the ServiceBehavior attribute
  • The method is decorated with the  OperationBehavior attribute
  • You will need a reference to the System.ServiceModel assembly that comes with the .NET environment

At the moment, our service might as well be replying “Bumblebee” to any request that it receives, because it’s not doing anything with it! So, let’s flesh out the implementation of the introduction:

And now we have implemented the business logic for our service!

Your service project should now look something like this:

WCF Windows Service Service

Service Host

Simply having an implementation is not enough! We need to have a way to actually host and run our implementation. There are several ways to accomplish this. For this article, I have decided to create a windows service using TopShelf and ServiceModelEx.

Using the NuGet Package Manager, add the TopShelf package to the service host project. Unfortunately, ServiceModelEx is not available on NuGet, so you will need to download the source (don’t worry, it’s free) from the IDesign downloads page. If you don’t feel like compiling it yourself, I have done so for you and uploaded a release build here. Add this DLL as a reference in the project, along with:

  1. The .NET assemblies:
    • System.ServiceModel
    • System.ServiceModel.Channels
  2. The solution projects:
    • WcfService.Contract
    • WcfService.Service

In the service host project, add a new class called Host:

This little bit of code utilizes the functionality provided by ServiceModelEx to create endpoints for the IntroductionService implementation and exposes it using WCF.

We need to modify the service host’s Main method:

This code uses the Topshelf functionality to create a Windows service. It’s really great – when you run this console application with no parameters, it’s a simple console application! However, there are a few switches that enable you to easily deploy the Windows service:

  • WcfService.WindowsService.exe install installs the service on the machine
  • WcfService.WindowsService.exe start starts the service (once installed)
  • WcfService.WindowsService.exe stop stops the service (if it has started)
  • WcfService.WindowsService.exe uninstall removes the service from the machine

For the more complex commands, the Topshelf Command-Line Reference will help.

Together, the two libraries provide a WCF Windows Service!

Configuration

In order for the service host to accept incoming connections, we need to add a little configuration. As this is a Windows service, I am going to expose the service as a net.tcp endpoint. This basically means that the protocol that the service will be communicating over is TCP, and the net prefix means that it was designed solely for .NET implementations (i.e. I don’t care about interoperability). You could be asking, “Why not expose it over the HTTP protocol and use SOAP?” The HTTP protocol is an application-layer protocol that runs on top of TCP, and we would therefore have to run our own application-layer on top of another one – HTTP! This extra step results in the service being inherently slower!

The configuration requires two parts in our configuration – a binding and an endpoint. Let’s get to it! Add a new Application Configuration file to the service host project and call it App.config:

WCF Windows Service Add Config

Paste the following XML into the App.config file:

So what are we doing here? Let’s break it down:

  1. Declaring a service with a name that exactly matches the service implementation’s namespace and class
  2. Assigning a base address to the service (i.e. each endpoint address declared will be appended to this base URI)
  3. Adding an endpoint to the service that uses the net.tcp protocol and promises to match the contract declared

Note: The address for the endpoint is empty, as this will be the default endpoint for this service.

Your service host project should look something like this:

WCF Windows Service Service Host

At this point in time, we can run the service host project, and the console application should start up:

WCF Windows Service Started

Testing the Service

There is a special tool that comes bundled with Visual Studio – a WCF Test Client. We can use this client to connect to our service to test it out! Unfortunately, this client (obviously), has no idea about the contract that we have just created! Fortunately for us, it is easy to get it to build its own contract! However, by default, our service does not give any of its secrets away! Not even its contract.

We need to make a couple of changes to our configuration file to allow us to test the service:

What have we changed? Let’s take a look:

  1. On line 5, we have configured the service to use a behavior, specified by name
  2. Lines 14-16 add a new endpoint to the service that allows metadata exchange (information about what contract the service will fulfill)
  3. Lines 19-25 configure the behavior we want to apply to the service

At this point, you can actually start the service host project and make test calls using the WCF Test Client that comes bundled with Visual Studio! The WcfTestClient.exe application can be found in the following folders:

  • C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE (for Windows 64-bit), or
  • C:\Program Files\Microsoft Visual Studio 11.0\Common7\IDE (for Windows 32-bit)

With the service host project running (make sure that you started it since modifying the App.config), start up the test client and click File → Add Service. Add the following connection to the client:

WCF Windows Service Test Client Connect

The client will then use the metadata exchange to add the service:

WCF Windows Service Test Client Adding

And finally, display the service that we have just implemented! Let’s give it a test. Select the Introduce() method, fill in the Greeting and Name values, check Start a new proxy and finally, click Invoke:

WCF Windows Service Test Client Result

Exciting, it works! So now that we’ve tested our service out, it’s time to write our own client application!

Client

Firstly, we need to know how to communicate with our WCF Windows Service, so the client needs a reference to the contract project.

Next up, we need some sort of way to create a connection to the service. I like this little proxy object (it’s lightweight, tried and tested):

This requires that the client project has a reference to the System.ServiceModel assembly that comes with the .NET framework. Furthermore, this assumes that there is an endpoint defined in the client’s App.config file that is named IIntroductionService_Endpoint, as highlighted below:

Notice that the endpoint is almost exactly the same as the service configuration! If you want a shortcut for the client side configuration, the WcfTestClient can actually generate the config file for you:

WCF Windows Service Test Client ConfigThere are a few differences between the generated config and the one I am actually using:

  • The name of the endpoint has been changed so that the WcfProxy<T>  above works
  • The bindings element and the bindingConfiguration attribute) have been removed as I am using the default netTcpBinding
  • I have qualified the contract attribute with the full namespace of the contract as it lives in another assembly

Calling the Service

And now, for the magic! In the Program.cs file in the client project, we are going to actually call the service. Let’s start off by calling the service using a hard-coded request. In the Main method, add the following code:

All we’re doing here is

  1. Creating an instance of our proxy to call the service
  2. Creating a request object and displaying it (in green)
  3. Sending it to the service and waiting for a response
  4. Once the response has come back, we are displaying it (in blue)

At this point, your project should look like this:

WCF Windows Service Client

We need to set up the service host and client projects to start up by default. Right click the solution in Solution Explorer, and click Set StartUp Projects

WCF Windows Service Startup Projects

 

Select the Multiple startup projects radio button, and set the service host and client projects to Start:

WCF Windows Service Startup Project Selected

Now, whenever we run the project, both projects will start in debug mode! Let’s start them up now! You should see the following in the client window:

WCF Windows Service Client Basic

That’s it! You’ve got a working solution for an application talking to a service over WCF!

Improving the Client

Just for fun, why don’t we allow the user to type in their own greeting and name. See if you can work through the modified code below and figure out what is going on:

You may now call the service with whichever greeting and name you like:

WCF Windows Service Client Improved

Gotchas and Notes

There are a couple of things that stumped me at first!

ServiceContract,  ServiceBehavior, OperationContract and OperationBehavior Attributes

Exceptions are thrown when trying to start up the service if these attributes are not added to the contract definitions and service implementations.

DataContract and DataMember Attributes

Adding a non-default constructor caused my classes to fail to serialize and/or deserialize without these attributes. If you want to add other properties that you don’t want serialized (e.g. calculated properties), just decorate the property with the  IgnoreDataMember attribute.

Deserializing Objects and Constructors

There is no need for a non-default constructor as the .NET serialization classes responsible for creating these objects in memory don’t use them! Give it a try – create a default constructor and do some custom initialization. This code never actually runs!

Download the Solution

If you would like to download the complete source code, the Visual Studio 2012 solution, projects and code (with ServiceModelEx.dll but without the NuGet packages) are available here

Final Thoughts

The steps to actually write software using an SOA approach are quite simple, aren’t they? All of our top-secret business logic sits safely in our data centers, out of the hands of the evil hackers!

This service does not actually hold any state or need to run any scheduled jobs, so it would work fine as a Web-Activated Service (WAS) hosted in Internet Information Services (IIS). Remember how we separated our service implementation from our service host? In order to implement this as a WAS, very few steps are necessary! Now I am going to do something that I really hate seeing on other blogs – a promise (not really) of another post! Well, here it is: I am planning on writing a post describing such a process in the near future.

posted on 2015-10-06 16:59  武胜-阿伟  阅读(1367)  评论(0编辑  收藏  举报