Recently I needed to set up some simple code to demonstrate WCF (as an alternative to some other means of communication in distributed applications). But when I googled around, I could not find a really, really simple WCF example. Sure, there are lots of WCF introductions, but they all explain a lot of stuff I did not really want to know at that time. Also they most often spread the code across many files and even across languages (C# and XML). And that´s what I really, really hate! When I first try out a new API like WCF I want to have everything needed in one (!) place. I want all that´s required to be the minimum and in my favorite programming language. This way I can focus best on what´s really essential without getting distracted by syntax and unnecessary (but cool) "fluff".
Finally I resorted to a book I wrote together with co-author Christian Weyer: ".NET 3.0 kompakt" (German). As you can imagine, I did not write the chapter on WCF, though ;-) In our book I found the most simple/gentle introduction to WCF and finally was able to set up my sample program within some 20 minutes. I only had to experiment a little for getting the client code to run without resorting to XML, since Christian did not show imperative code for it in the book.
Now, to make life easier for you, I present to you the most simple WCF application I can think of in one piece. Copy the pieces into a VS 2005 console project, reference the System.ServiceModel library from .NET 3.0 and off you go. The code should run right out of the box.
Although I don´t want to repeat what´s been said in our book or in others like "Programming WCF Services" by Juval Löwy or elsewhere on the web about WCF (e.g. here http://msdn2.microsoft.com/en-us/library/aa480190.aspx or here http://www.devx.com/dotnet/Article/29414 or here http://bloggingabout.net/blogs/dennis/archive/2006/10/18/WCF-Part-0-_3A00_-Introduction.aspx), I think it´s in order to give you a quick tour through my code:
My simple sample service is of course trivial, since I´m not interested in service functionality but getting the WCF infrastructure to run. So my service WCFSimple.Contract.IService just consists of a single method - Ping() - which accepts a name and responds with a greeting. Passing in "Peter" returns "Hello, Peter".
Defining a WCF service means defining its functionality in a so called service contract which is given as an interface here. That this interface is a service contract and which of its methods should be published is signified by the attributes.
Once you´ve defined a service you can implement it. Just define a class that implements the service´s interface (line 22, 26..30). The ServiceBehaviour attribute in this case tells the WCF infrastructure to create a fresh instance of the service class for each call to the service´s methods. It´s the same as .NET Remoting´s SingleCall wellknown objects. Of course, though, I could have chosen a different instanciation mode, but I wanted to avoid any side effects due to state issues.
I chose to set up the server for my service implementation just on a separate thread in my sample app. But to make it easier for you to move it to a process/project of its own, I let it look like the default class of a console application.
In order to host a service, the Main() method creates a ServiceHost to manage any service implementation instances and publish the service on any number of endpoints. I chose to make the service accessible just through one endpoint, though. And this I do explicitly in code - instead of through some App.Config settings. That way I get to know how the WCF parts work together.
The endpoint takes as a first argument the service definition (contract), since the class I passed to the ServiceHost could possibly implement several services. Then I specify the "communication medium", the binding. TCP seems to be suffcient for my purposes. Finally I set up the endpoint at a particular address that surely needs to match the binding. For TCP I specify an IP address (or domain name) and a port.
That´s it. WCF can be as simple as the ABC: Address+Binding+Contract=Endpoint.
Now I just need to start the ServiceHost with Open() and later on finish it with Close(). However, since the service host is doing its work on a separate thread, I cannot just move on after Open(). I have to wait for a signal telling the server to stop. For that purpose I set up a WaitHandle - stopFlag - which can be signalled from the outside through the Stop() method.
If you put the server in a console app of its own, you can remove the WaitHandle stuff and replace the stopFlag.WaitOne() with just a Console.ReadLine().
Warning: The Close() takes at least 10 sec to complete, as it seems. This is to give any still connected clients the chance to disconnect, as far as I understand right now. So if you don´t happen to see the "Shut down!" message when running the sample, don´t worry.
The client in this sample has two tasks: 1) start the server, 2) call the server.
To run client and server in the same process, the server is started in a background thread of its own (lines 75..77). To give it some time to become ready to serve requests, a delay of 1 sec is added afterwards. Also this avoids a mess of messages shown in the console window at start up ;-)
Next the client sets up a channel along which the request can flow between it and the server. To create a channel, a channel factory is needed (line 81f), though. It can create channels for a certain contract, a specific binding, and targeting an address (lines 82..84). Again the ABC of WCF.
Creating a channel with the channel factory then returns a proxy of the remote server which looks like the implementation - but in fact is a channel, i.e. a WCF object (line 86f).
The rest of the code is just a bit of frontend logic: a loop to ask for a name, passing it to the service, and displaying the returned greeting. Just hit enter without a name to end the loop.
Once the loop is terminated, the server is stopped. Before that, though, you should close the proxy! Otherwise the shutdown of the server will take some time, because it first waits for the client.
Just be sure to download .NET 3.0 and reference System.ServiceModel. The rest is just copying the above code parts in order into a console project and hit F5.
Enjoy!
PS: If you wonder, how I got those pretty listings into my posting, let me point you to CopySourceAsHtml (CSAH). It´s a great tool for anybody who wants to paste code into a blog at least while using Windows Live Writer. Although I have to switch to HTML view to do that, which is a bit cumbersome, I love both tools.
Finally I resorted to a book I wrote together with co-author Christian Weyer: ".NET 3.0 kompakt" (German). As you can imagine, I did not write the chapter on WCF, though ;-) In our book I found the most simple/gentle introduction to WCF and finally was able to set up my sample program within some 20 minutes. I only had to experiment a little for getting the client code to run without resorting to XML, since Christian did not show imperative code for it in the book.
Now, to make life easier for you, I present to you the most simple WCF application I can think of in one piece. Copy the pieces into a VS 2005 console project, reference the System.ServiceModel library from .NET 3.0 and off you go. The code should run right out of the box.
Although I don´t want to repeat what´s been said in our book or in others like "Programming WCF Services" by Juval Löwy or elsewhere on the web about WCF (e.g. here http://msdn2.microsoft.com/en-us/library/aa480190.aspx or here http://www.devx.com/dotnet/Article/29414 or here http://bloggingabout.net/blogs/dennis/archive/2006/10/18/WCF-Part-0-_3A00_-Introduction.aspx), I think it´s in order to give you a quick tour through my code:
Service definition
1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4
5 using System.ServiceModel;
6
7
8 namespace WCFSimple.Contract
9 {
10 [ServiceContract]
11 public interface IService
12 {
13 [OperationContract]
14 string Ping(string name);
15 }
16 }
Defining a WCF service means defining its functionality in a so called service contract which is given as an interface here. That this interface is a service contract and which of its methods should be published is signified by the attributes.
Service implementation
19 namespace WCFSimple.Server
20 {
21 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
22 class ServiceImplementation : WCFSimple.Contract.IService
23 {
24 #region IService Members
25
26 public string Ping(string name)
27 {
28 Console.WriteLine("SERVER - Processing Ping('{0}')", name);
29 return "Hello, " + name;
30 }
31
32 #endregion
33 }
Hosting the service, implementing the server
36 public class Program
37 {
38 private static System.Threading.AutoResetEvent stopFlag = new System.Threading.AutoResetEvent(false);
39
40 public static void Main()
41 {
42 ServiceHost svh = new ServiceHost(typeof(ServiceImplementation));
43 svh.AddServiceEndpoint(
44 typeof(WCFSimple.Contract.IService),
45 new NetTcpBinding(),
46 "net.tcp://localhost:8000");
47 svh.Open();
48
49 Console.WriteLine("SERVER - Running...");
50 stopFlag.WaitOne();
51
52 Console.WriteLine("SERVER - Shutting down...");
53 svh.Close();
54
55 Console.WriteLine("SERVER - Shut down!");
56 }
57
58 public static void Stop()
59 {
60 stopFlag.Set();
61 }
62 }
63 }
In order to host a service, the Main() method creates a ServiceHost to manage any service implementation instances and publish the service on any number of endpoints. I chose to make the service accessible just through one endpoint, though. And this I do explicitly in code - instead of through some App.Config settings. That way I get to know how the WCF parts work together.
The endpoint takes as a first argument the service definition (contract), since the class I passed to the ServiceHost could possibly implement several services. Then I specify the "communication medium", the binding. TCP seems to be suffcient for my purposes. Finally I set up the endpoint at a particular address that surely needs to match the binding. For TCP I specify an IP address (or domain name) and a port.
That´s it. WCF can be as simple as the ABC: Address+Binding+Contract=Endpoint.
Now I just need to start the ServiceHost with Open() and later on finish it with Close(). However, since the service host is doing its work on a separate thread, I cannot just move on after Open(). I have to wait for a signal telling the server to stop. For that purpose I set up a WaitHandle - stopFlag - which can be signalled from the outside through the Stop() method.
If you put the server in a console app of its own, you can remove the WaitHandle stuff and replace the stopFlag.WaitOne() with just a Console.ReadLine().
Warning: The Close() takes at least 10 sec to complete, as it seems. This is to give any still connected clients the chance to disconnect, as far as I understand right now. So if you don´t happen to see the "Shut down!" message when running the sample, don´t worry.
Running the server, implementing the client
66 namespace WCFSimple
67 {
68 class Program
69 {
70 static void Main(string[] args)
71 {
72 Console.WriteLine("WCF Simple Demo");
73
74 // start server
75 System.Threading.Thread thServer = new System.Threading.Thread(WCFSimple.Server.Program.Main);
76 thServer.IsBackground = true;
77 thServer.Start();
78 System.Threading.Thread.Sleep(1000); // wait for server to start up
79
80 // run client
81 ChannelFactory<WCFSimple.Contract.IService> scf;
82 scf = new ChannelFactory<WCFSimple.Contract.IService>(
83 new NetTcpBinding(),
84 "net.tcp://localhost:8000");
85
86 WCFSimple.Contract.IService s;
87 s = scf.CreateChannel();
88
89 while (true)
90 {
91 Console.Write("CLIENT - Name: ");
92 string name = Console.ReadLine();
93 if (name == "") break;
94
95 string response = s.Ping(name);
96 Console.WriteLine("CLIENT - Response from service: " + response);
97 }
98 (s as ICommunicationObject).Close();
99 // shutdown server
100 WCFSimple.Server.Program.Stop();
101 thServer.Join();
102 }
103 }
104 }
To run client and server in the same process, the server is started in a background thread of its own (lines 75..77). To give it some time to become ready to serve requests, a delay of 1 sec is added afterwards. Also this avoids a mess of messages shown in the console window at start up ;-)
Next the client sets up a channel along which the request can flow between it and the server. To create a channel, a channel factory is needed (line 81f), though. It can create channels for a certain contract, a specific binding, and targeting an address (lines 82..84). Again the ABC of WCF.
Creating a channel with the channel factory then returns a proxy of the remote server which looks like the implementation - but in fact is a channel, i.e. a WCF object (line 86f).
The rest of the code is just a bit of frontend logic: a loop to ask for a name, passing it to the service, and displaying the returned greeting. Just hit enter without a name to end the loop.
Once the loop is terminated, the server is stopped. Before that, though, you should close the proxy! Otherwise the shutdown of the server will take some time, because it first waits for the client.
Summary
That´s it. That´s my very simplest WCF example. It lets you play around with WCF in a single process. Or you can easily distribute the code across several assemblies: one for the server and implementation, one for the client, and one for the contract shared between the two.Just be sure to download .NET 3.0 and reference System.ServiceModel. The rest is just copying the above code parts in order into a console project and hit F5.
Enjoy!
PS: If you wonder, how I got those pretty listings into my posting, let me point you to CopySourceAsHtml (CSAH). It´s a great tool for anybody who wants to paste code into a blog at least while using Windows Live Writer. Although I have to switch to HTML view to do that, which is a bit cumbersome, I love both tools.
0 comments:
Post a Comment