标签:
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:
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:
So what actually makes up a service interaction? There are four necessary elements:
We can think of the contract as an agreement between the client and service as to how they will be communicating.
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:
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:
Without such a contract in place, you might imagine the following interaction:
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).
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!
In Visual Studio, start with an empty solution. We need to add 4 projects to the solution:
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.
We discussed how contracts describe what is necessary for an interaction to occur earlier. There are three parts to this:
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:
Let’s add the contract now – add a new interface called IIntroductionService:
Notice a few things about this interface:
Your contract project should now look something like this:
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?
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:
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:
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:
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:
For the more complex commands, the Topshelf Command-Line Reference will help.
Together, the two libraries provide a WCF Windows Service!
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:
Paste the following XML into the App.config file:
So what are we doing here? Let’s break it down:
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:
At this point in time, we can run the service host project, and the console application should start up:
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:
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:
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:
The client will then use the metadata exchange to add the service:
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:
Exciting, it works! So now that we’ve tested our service out, it’s time to write our own client application!
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:
There are a few differences between the generated config and the one I am actually using:
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
At this point, your project should look like this:
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…
Select the Multiple startup projects radio button, and set the service host and client projects to Start:
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:
That’s it! You’ve got a working solution for an application talking to a service over WCF!
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:
There are a couple of things that stumped me at first!
Exceptions are thrown when trying to start up the service if these attributes are not added to the contract definitions and service implementations.
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.
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!
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
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.
WCF Windows Service Using TopShelf and ServiceModelEx z
标签:
原文地址:http://www.cnblogs.com/zeroone/p/4857365.html