DESKTOP

Communicate Between Processes on the Same Machine (WCF)

9/26/2010 7:51:34 PM
Use Windows Communication Foundation (WCF) with named pipe bindings.

Before WCF, you had many, many communications choices, including COM, DCOM, .NET Remoting, SOAP, TCP/IP, HTTP, named pipes, and more. WCF wraps all of those into a single framework. It separates what you communicate from how you communicate. As you’ll see, you can change from using named pipes to HTTP with only configuration changes.

WCF was designed from the ground up to unify communication technologies under a single framework. This allows your apps to be resilient to change when you need to modify how they communicate. In addition, you get an enormous amount of supporting abilities like security, auditing, extensibility, and more. If you need to use more than one protocol, you can interact with both of them through the common interface of WCF rather than worrying about protocol specifics. WCF can be in command-line apps, GUIs, Windows services, or IIS components.

WCF is a large enough topic for its own book (or series of books), but we’ll present enough to get you started.

A WCF app generally has three components:

  • A service interface and implementation. This can be implemented in the same assembly as the server, but it can be useful to keep it in a separate assembly so that it can be used in multiple hosts if needed.

  • A server that hosts the service implementation.

  • A client that calls the server via a proxy class that implements the library’s interfaces.

This section will handle each component in turn.

Define the Service Interface

The service in this example will be a simple file server that implements three methods to retrieve directory and file data for the client. The methods are defined in an interface inside a class library that the server references and implements.

using System;
using System.ServiceModel;

namespace FileServiceLib
{
[ServiceContract]
public interface IFileService
{
[OperationContract]
string[] GetSubDirectories(string directory);

[OperationContract]
string[] GetFiles(string directory);

[OperationContract]
int RetrieveFile(string filename, int amountToRead,
out byte[] bytes);
}
}

The attributes on the interface and methods tell WCF that these should be part of the service.

The implementation is simple:

using System;
using System.ServiceModel;
using System.IO;

namespace FileServiceLib
{
public class FileService : FileServiceLib.IFileService
{
//just because it's a file service doesn't mean that you have to
//actually use the real underlying file system--you could make
//your own virtual file system
public string[] GetSubDirectories(string directory)
{
return System.IO.Directory.GetDirectories(directory);
}

public string[] GetFiles(string directory)
{
return System.IO.Directory.GetFiles(directory);
}

public int RetrieveFile(string filename, int amountToRead,
out byte[] bytes)
{
bytes = new byte[amountToRead];
using (FileStream stream = File.OpenRead(filename))
{
return stream.Read(bytes, 0, amountToRead);
}
}
}
}


See the FileServiceLib project in the accompanying source code.

Create the Server

In this case, the server is going to be a console application for simplicity. You could just as easily make it part of a Windows service or run it under IIS.

using System;
using System.ServiceModel;
using FileServiceLib;

namespace WCFHost
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("FileService Host");
//tell WCF to start our service using the
//info in app.config file
using (ServiceHost serviceHost =
new ServiceHost(typeof(FileServiceLib.FileService)))
{
serviceHost.Open();

Console.ReadLine();
}
}
}
}

The configuration file is where the action is. In this case, it tells WCF to use named pipes to communicate with clients, which is ideal for processes located on the same machine.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="FileServiceLib.FileService"
behaviorConfiguration="FileServiceMEXBehavior">
<endpoint address=""
binding="netNamedPipeBinding"
contract="FileServiceLib.IFileService"/>
<!-- a MEX endpoint allows WCF to exchange
metadata about your connection -->
<endpoint address="mex"
binding="mexNamedPipeBinding"
contract="IMetadataExchange"/>-->
<host>
<baseAddresses>
<add baseAddress="net.pipe://localhost/FileService"/>
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="FileServiceMEXBehavior">
<serviceMetadata />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>


See the WCFHost project in the accompanying source code.

Create the Client

To allow the client to communicate with the server seamlessly, without any knowledge of the underlying protocols, you need a proxy class, which converts normal method calls into WCF commands that eventually translate into bytes that go over the connection to the server. You could create this class by hand, but it’s easier to start up the server and run a utility to generate it for you.

The file svcutil.exe ships with the Windows SDK. It generates two files: a C# code file with the proxy class implementation, and a configuration file to use in the client.

My copy of svcutil.exe is located in C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\. Your location may vary. After starting the server, I ran the following command at the console:

D:\>"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\SvcUtil.exe " net.pipe://localhost/FileService /out:FileServiceLib_Proxy.cs/config:app.config

Note

Visual Studio can also generate a proxy class for you in the Add Service Reference dialog box. However, if you have multiple developers working on a project, you should stick to using svcutil.exe because Visual Studio generates additional metadata files that also need to be checked in, but these can be different on different machines, which can cause headaches. It’s better to just avoid it completely.


Note

The proxy is generated for the interface and is the same regardless of which protocol is used. This allows you to make protocol changes in the configuration without having to rebuild the application.


In this example, the client will be a WinForms app that allows you to call each service method and then shows the results.

First, add both of the svcutil.exe-generated files to the project. The app.config file looks similar to this:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<netNamedPipeBinding>
<binding name="NetNamedPipeBinding_IFileService"
closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00"
sendTimeout="00:01:00"
transactionFlow="false" transferMode="Buffered"
transactionProtocol="OleTransactions"
hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288"
maxBufferSize="65536" maxConnections="10"
maxReceivedMessageSize="65536">
<readerQuotas maxDepth="32"
maxStringContentLength="8192"
maxArrayLength="16384"
maxBytesPerRead="4096"
maxNameTableCharCount="16384" />
<security mode="Transport">
<transport protectionLevel="EncryptAndSign" />
</security>
</binding>
</netNamedPipeBinding>
</bindings>
<client>
<endpoint address="net.pipe://localhost/FileService"
binding="netNamedPipeBinding"
bindingConfiguration
= "NetNamedPipeBinding_IFileService"
contract="IFileService"
name="NetNamedPipeBinding_IFileService">
<identity>
<userPrincipalName value="Ben-Desktop\Ben" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>


The proxy class has the name FileServiceClient, so to instantiate and use it looks something like this:

using System;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WCFClient
{
public partial class Form1 : Form
{
FileServiceClient fsClient = null;

public Form1()
{
InitializeComponent();

fsClient = new FileServiceClient();
}
private void buttonGetSubDirs_Click(object sender, EventArgs e)
{
SetResults(fsClient.GetSubDirectories(
textBoxGetSubDirs.Text));
}

private void buttonGetFiles_Click(object sender, EventArgs e)
{
SetResults(fsClient.GetFiles(textBoxGetFiles.Text));
}

private void buttonGetFileContents_Click(object sender,
EventArgs e)
{
int bytesToRead = (int)numericUpDownBytesToRead.Value;
byte[] buffer = new byte[bytesToRead];
int bytesRead =
fsClient.RetrieveFile(out buffer,
textBoxRetrieveFile.Text,
bytesToRead);

if (bytesRead > 0)
{
//just assume ASCII for this example
string text = Encoding.ASCII.GetString(buffer,
0,
bytesRead);
SetResults(text);
}
}

private void SetResults(string[] results)
{
//use LINQ to concat the results easily
textBoxOutput.Text =
results.Aggregate((a, b) => a + Environment.NewLine + b);
}

private void SetResults(string results)
{
textBoxOutput.Text = results;
}
}
}


Figure 1 shows the client running on the same machine as the server.

Figure 1. The client communicates via the server over named pipes.


There is a lot more to WCF, but the power of the framework should be apparent.

Other  
 
Most View
Samsung Home Theatre Series With Wireless Connection
MSI GT70 Notebook - Power Play
Compact Cameras For The Dynamic
Review: lcy Box Stand For iPad
Better Than Expected Showing (Part 2)
G Data Total Protection 2013 - Innovative Fingerprinting Technique
ECS Z77H2-A2X v1.0 - Golden LGA 1155 Mainboard From The Black Series (Part 3)
Free VirtualBox Images (Part 2) - Create your own VirtualBox image
Improve Your Mac (Part 4) - Tips for saving bandwidth
The Modern Office (Part 2)
Top 10
Nikon Coolpix A – An Appealing Camera For Sharp Images (Part 2)
Nikon Coolpix A – An Appealing Camera For Sharp Images (Part 1)
Nikon Coolpix L28 Camera - Ideal Choice For Limited Budgets
Antec GX700 Value Gaming Computer Case
BenQ W703D - Wallet-Friendly Wonder
Canon Pixma Pro-10 A3+ Professional Printer (Part 2)
Canon Pixma Pro-10 A3+ Professional Printer (Part 1)
Dell XPS 12 Convertible Ultrabook Review (Part 3)
Dell XPS 12 Convertible Ultrabook Review (Part 2)
Dell XPS 12 Convertible Ultrabook Review (Part 1)