What the heck is WCF? For a long time, I couldn't tell you exactly what it was. And honestly, I still don't think I can. WCF is such a broad concept that it's hard to boil down into a concise explanation. When I finally started reading about it, and getting beyond the concepts, things started to clear up. That's what today's tutorial is about - cutting through all the concepts and just use WCF to build a basic server and a basic client.
At its core, WCF is a mechanism that facilitates communication between processes - either on the same machine or separate machines. Part of the confusion I had when trying to understand WCF was the almost limitless ways WCF can accomplish this. We're not going to worry about all of that though. We're going to strip out everything except the bare essentials required to get a client/server system up and running - and it's actually very little code.
What we're building today will look a lot like a simple remote procedure call. We'll be building a server that exposes a function that can be called by a client. Just to show how easy it is to change the transport layer, the client will connect to the server through two different mechanisms - http and named pipe.
The first thing we need to do is define what the client will have access to. We do this by defining an interface in C# and giving it a few attributes for WCF. The server will create a class that implements the interface to actually do the work. The client will just be provided the interface so it knows which functions are available.
using System.ServiceModel;
[ServiceContract]
public interface IStringReverser
{
[OperationContract]
string ReverseString(string value);
}
Here's my simple interface. It provides a function that takes a string and returns a new string with all of the characters reversed. The ServiceContract attribute tells WCF that this interface can be exposed for client use. The OperationContract attributes tells WCF that ReverseString is part of this service contract and can be used by clients. There are lots of optional settings that can be applied to both of these attributes, but this is all that's required to get things up and running. The System.ServiceModel namespace is available by adding a reference to the System.ServiceModel assembly to your project, which is available in the default installation of .NET 3.5.
Starting with the server, the first thing we need to do is create a class that implements this interface and provides the functionality behind ReverseString.
using System.ServiceModel;
[ServiceContract]
public interface IStringReverser
{
[OperationContract]
string ReverseString(string value);
}
public class StringReverser : IStringReverser
{
public string ReverseString(string value)
{
char[] retVal = value.ToCharArray();
int idx = 0;
for (int i = value.Length - 1; i >= 0; i--)
retVal[idx++] = value[i];
return new string(retVal);
}
}
Pretty simple, right? There might be more elegant ways to reverse a string, but we're not here to criticize the implementation of this function. It's actually not required to use the interface method for defining service contracts (i.e. you could stick the attributes directly on the class), but it's the recommended way, and it makes client applications much easier to implement if they can simply share the same interfaces.
Surprisingly, there's actually very little code required to make the server fully functional. We'll begin by creating a ServiceHost, which is responsible for most of the work behind exposing the service to clients.
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(
typeof(StringReverser),
new Uri[]{
new Uri("http://localhost:8000"),
new Uri("net.pipe://localhost")
}))
{
}
}
}
The most difficult thing here is the array of Uri objects. These are our base addresses that clients can use to connect to this WCF server. Like I said before, we're exposing two ways to connect to this service: http and named pipe. How the address is formatted depends on the type of Binding it represents.
Now that we've got our ServiceHost created, we need to configure some endpoints. These will actually enable the http and named pipe bindings and give them the address required by the client.
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(
typeof(StringReverser),
new Uri[]{
new Uri("http://localhost:8000"),
new Uri("net.pipe://localhost")
}))
{
host.AddServiceEndpoint(typeof(IStringReverser),
new BasicHttpBinding(),
"Reverse");
host.AddServiceEndpoint(typeof(IStringReverser),
new NetNamedPipeBinding(),
"PipeReverse");
host.Open();
Console.WriteLine("Service is available. " +
"Press <ENTER> to exit.");
Console.ReadLine();
host.Close();
}
}
}
Here we're adding two endpoints - one for http and one for named pipe. The address that's passed in is what appears after the base address specified in the ServiceHost constructor (e.g. for http it would be: "http://localhost:8000/Reverse"). We have to specify a base address for each endpoint we're configuring. So if the net.pipe base address was not present in the ServiceHost constructor, the server would throw an exception when it attempted to create the named pipe endpoint. After the endpoints are configured, we simply call Open on the ServiceHost to enable it.
Believe or not, that's it for a fully functional WCF server. Below is all of the code put together.
using System.ServiceModel;
namespace WCFServer
{
[ServiceContract]
public interface IStringReverser
{
[OperationContract]
string ReverseString(string value);
}
public class StringReverser : IStringReverser
{
public string ReverseString(string value)
{
char[] retVal = value.ToCharArray();
int idx = 0;
for (int i = value.Length - 1; i >= 0; i--)
retVal[idx++] = value[i];
return new string(retVal);
}
}
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(
typeof(StringReverser),
new Uri[]{
new Uri("http://localhost:8000"),
new Uri("net.pipe://localhost")
}))
{
host.AddServiceEndpoint(typeof(IStringReverser),
new BasicHttpBinding(),
"Reverse");
host.AddServiceEndpoint(typeof(IStringReverser),
new NetNamedPipeBinding(),
"PipeReverse");
host.Open();
Console.WriteLine("Service is available. " +
"Press <ENTER> to exit.");
Console.ReadLine();
host.Close();
}
}
}
}
Now we can move on to the client. The first thing we'll need in the client code is the same interface, with the same attributes, that we defined in the server. If this were being used in a production environment, these interfaces would probably be created in a dedicated library that could be easily distributed. For now, I just copied and pasted the code into another project.
We have to first establish a channel between the client and a server. A channel is basically a connection that allows the client and server to send messages to each other. Fortunately, WCF provides something called a ChannelFactory that makes creating these very simple.
using System.ServiceModel;
using System.ServiceModel.Channels;
namespace WCFClient
{
[ServiceContract]
public interface IStringReverser
{
[OperationContract]
string ReverseString(string value);
}
class Program
{
static void Main(string[] args)
{
ChannelFactory<IStringReverser> httpFactory =
new ChannelFactory<IStringReverser>(
new BasicHttpBinding(),
new EndpointAddress(
"http://localhost:8000/Reverse"));
ChannelFactory<IStringReverser> pipeFactory =
new ChannelFactory<IStringReverser>(
new NetNamedPipeBinding(),
new EndpointAddress(
"net.pipe://localhost/PipeReverse"));
IStringReverser httpProxy =
httpFactory.CreateChannel();
IStringReverser pipeProxy =
pipeFactory.CreateChannel();
}
}
}
We're building two proxies here - one for http and one for named pipe. The addresses passed into the ChannelFactory constructor are the same as those configured on the server. We also have to pass in the specific bindings we want: BasicHttpBinding and NetNamedPipeBinding. Lastly we call CreateChannel on each channel factory, which returns an IStringReverser interface. Now we can call functions on those interfaces and WCF makes a remote call through the channel to our server to get the result.
Console.WriteLine("http: " + httpProxy.ReverseString(str));
Console.WriteLine("pipe: " + pipeProxy.ReverseString(str));
Incredibly, we're now done with the client. Here's the client program in its entirety:
using System.ServiceModel;
using System.ServiceModel.Channels;
namespace WCFClient
{
[ServiceContract]
public interface IStringReverser
{
[OperationContract]
string ReverseString(string value);
}
class Program
{
static void Main(string[] args)
{
ChannelFactory<IStringReverser> httpFactory =
new ChannelFactory<IStringReverser>(
new BasicHttpBinding(),
new EndpointAddress(
"http://localhost:8000/Reverse"));
ChannelFactory<IStringReverser> pipeFactory =
new ChannelFactory<IStringReverser>(
new NetNamedPipeBinding(),
new EndpointAddress(
"net.pipe://localhost/PipeReverse"));
IStringReverser httpProxy =
httpFactory.CreateChannel();
IStringReverser pipeProxy =
pipeFactory.CreateChannel();
while (true)
{
string str = Console.ReadLine();
Console.WriteLine("http: " +
httpProxy.ReverseString(str));
Console.WriteLine("pipe: " +
pipeProxy.ReverseString(str));
}
}
}
}
It's amazing when you think about the amount of stuff happening behind the scenes that developers no longer have to worry about. Basically, all developers have to do is define interfaces and objects and WCF takes care of the rest. The server side and client side code can be drastically reduced by using configuration files to replace the setup we did in code, but for the purpose of understanding, explicitly setting it is a good way to know what's behind configuration settings.
I think that about wraps it up for this introduction to WCF. There's an immense amount of configuration and customization supported by WCF, and volumes could be dedicated to it. Hopefully we'll slowly unravel WCF's complexity and introduce new concepts in following tutorials. You can download Visual Studio 2008 solutions for both the client and the server here.
12/23/2008 - 14:33
what is meant by end point can you explain those briefly
03/31/2009 - 00:04
the client who connects is known as the end point.
Regards,
Kathirvel
01/07/2009 - 11:36
I implemented a WCF web service for a client recently, and it works great - so I definitely don’t need to be sold on it.
However, now I’m doing research for another client who would like a real-time chat app. I’m trying to find out what, if any, are the differences between implementing a WCF server app and implementing a Socket server app? I’ve heard that WCF doesn’t allow tcp/ip connections beyond LAN boundaries but I’m not sure if that’s accurate or not. I’ve also heard that one cannot create persistent tcp/ip connections with WCF, but like the previous statement that did not come from an authority on the matter.
Do you have any insight? Have you attempted to create any kind of RTM app with WCF?
02/03/2009 - 06:22
Thanku very much for the sample code provided. The code helped me in finding a design solution for my application gud work
04/21/2009 - 09:35
You better explain main concepts of WCF before jumping on code.That is one problem as most developers want to do stuff in minutes without understanding the main concepts. Look at one reader, he/she didnt understand end point.me too.
i think microsoft gave the archecture to WCF pretty same as .Net Remoting.
04/21/2009 - 10:32
It is always nice to explain the basics, but not every post is going to do that. You mention that most developers want to do stuff very quickly, this isn't something I think is always wanted but needed. I find that sometimes things just need to get done. Also, if you don't understand some of the basics I think that you should take some initiative to learn them before jumping into code. Now, maybe we should have a few more links for the basic information.
04/23/2009 - 08:18
very true for the sentence "this isn't something I think is always wanted but needed. I find that sometimes things just need to get done." I just explore WCF and campared WCF vs Web services and got point , actually WCF gonna be next communication platform leaving behind webservice for sack of a true SOA architecture.Good work in your example.
06/26/2009 - 02:11
Hi,
I have an application architecture in which I have one WCF service and multiple .net applications on same machine. Since everything resides on same machine I'm using namedPipeTcp. .Net application/s calls the WCF service and WCF service stores the callback channel of each application in it, since it (WCF service) might need to call .Net application's side method later. Its a duplex channel mechanism. But the scenario is not Actually a async operation where request is made to WCF service and reply it sent back after some time.
it is just that WCF service stores the callback channel of each application and whenever it wants to send any other message to .net client it uses the stored callback. Everything works great!!!
Instead of this architecture, we have another option..that, have one WCF service and each .net application will again host its own WCF service.. So whenever, main WCF wants to send message to .Net application it will actually send message to WCF service residing in that application.
Can you please let me know advantages/disadavantgs of both of these approaches?
Thanks
Rahul
06/26/2009 - 08:31
Option 1 definitely sounds like a cleaner approach.
Since you're using named pipes, if you were to do option 2 each client you create would have to create a service using a unique named pipe. You would then have to add the ability for each client to give the main service the new pipe name so it could then connect back to it.
From a performance and resource standpoint, option 1 is much better. Named pipes provide duplex communication, so you should use it. Option 2 basically mimics duplex communication using multiple one-way communication paths.
Unless the callback system doesn't provide all the functionality you need, I wouldn't recommend changing to option 2. The architecture you created is basically straight from Microsoft's recommendations.
Add Comment
[language] [/language]
Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]
See here for supported languages.
Javascript must be enabled to submit anonymous comments - or you can login.