Sei sulla pagina 1di 25

Windows Communication Foundation (WCF) is an SDK for developing and deploying

services on Windows. WCF provides a runtime environment for your services, enabling
you to expose CLR types as services, and to consume other services as CLR types.
Although in theory you could build services without WCF, in practice building services is
significantly easier with WCF. WCF is Microsoft’s implementation of a set of industry
standards defining service interactions, type conversion, marshaling, and various
protocols’ management. Because of that, WCF provides interoperability between
services. WCF provides developers with the essential off-the-shelf plumbing required by
almost any application, and as such, it greatly increases productivity. The first release of
WCF provides many useful facilities for developing services, such as hosting, service
instance management, asynchronous calls, reliability, transaction management,
disconnected queued calls, and security. WCF also has an elegant extensibility model that
you can use to enrich the basic offering. In fact, WCF itself is written using this
extensibility model. The rest of the chapters in this book are dedicated to those aspects
and features. Most all of the WCF functionality is included in a single assembly called
System.ServiceModel.dll in the System.ServiceModel namespace.

WCF is part of .NET 3.0 and requires .NET 2.0, so it can only run on operation systems
that support it. Presently this list consists of Windows Vista (client and server), Windows
XP SP2, and Windows Server 2003 SP1 or their later versions.

WCF - Creating and Implementing a


Service in C#
Category: .NET Framework

WCF - Creating a Service and Client in ASP.NET 3.5 and C#

Introduction

The Windows Communication Foundation (WCF) is great for allowing applications to


interact and integrate with one another across platforms. WCF is a powerful introduction
to the .NET Framework, aimed at filling gaps left by such implementations as Web
Services, and this article will guide you through creating a simple WCF Service, and then
implementing that Service with a Client. We can host the Service on the same machine as
the Client, which is great for testing. This article will result in us creating a simple
calculator service, that we can consume in a client. The Client will call the service to use
the simple calculator tasks of addition, subtract, multiply and divide.

What we will learn in this article:


• How to Create a WCF Service in Visual Studio.NET 2008;
• How to consume the WCF Service in a Client Console application.

Please Note:
To create this example WCF Service, we will be using Visual Studio.NET 2008 with
ASP.NET 3.5, which comes with WCF built-in. However, this article will make use of the
CMD Shell from the Windows SDK to build the client application, which can be
downloaded from Microsoft here

Getting Started with our WCF Service


To begin, we will start up Visual Studio and create a New Project, Console Application.
We will start with our WCF Service. Name it Service1, and choose a location. When the
project opens, we should see something like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ProgrammingHelp.WCFService1
{
class Program
{
static void Main(string[] args)
{
}
}
}

Our next step is to add a reference to the ServiceModel.dll. To do this, right-click on the
References folder in Solution Explorer, and choose Add Reference. In the ASP.NET Tab,
scroll down to System.ServiceModel, select it and click Ok. Now add a using directive:

using System.ServiceModel;

If you're ever in the market for some great Windows web hosting, try Server Intellect. We
have been very pleased with their services and most importantly, technical support.

Now we can create our interface for the calculator, which includes our Operation
Contracts. The contract defines the functionality offered by the Service, and describes
how to use it. Add the following to the namespace:

[ServiceContract(Namespace = "http://ProgrammingHelp.Service/")]
public interface ICalculator
{
[OperationContract]
Double Add(Double n1, Double n2);
[OperationContract]
Double Subtract(Double n1, Double n2);
[OperationContract]
Double Multiply(Double n1, Double n2);
[OperationContract]
Double Divide(Double n1, Double n2);
}

Now to implement this contract, we create the methods in a class which inherits our
interface:

class CalculatorService : ICalculator


{
public Double Add(Double num1, Double num2)
{
Double answer = num1 + num2;
Console.WriteLine("Call made: Add({0},{1})", num1, num2);
Console.WriteLine("Answer: {0}", answer);
return answer;
}

public Double Subtract(Double num1, Double num2)


{
Double answer = num1 - num2;
Console.WriteLine("Call made: Subtract({0},{1})", num1, num2);
Console.WriteLine("Answer: {0}", answer);
return answer;
}

public Double Multiply(Double num1, Double num2)


{
Double answer = num1 * num2;
Console.WriteLine("Call made: Multiply({0},{1})", num1, num2);
Console.WriteLine("Answer: {0}", answer);
return answer;
}

public Double Divide(Double num1, Double num2)


{
Double answer = num1 / num2;
Console.WriteLine("Call made: Divide({0},{1})", num1, num2);
Console.WriteLine("Answer: {0}", answer);
return answer;
}
}

Server Intellect assists companies of all sizes with their hosting needs by offering fully
configured server solutions coupled with proactive server management services. Server
Intellect specializes in providing complete internet-ready server solutions backed by their
expert 24/365 proactive support team.

Now we will create the Main object inside the Program class. This will add the Service
EndPoint and ultimately initialize our Service. Here, we will use the
ServiceMetadataBehavior class, which is in the System.ServiceModel.Description
namespace. We will need to also add a reference to this.

class Program
{
static void Main(string[] args)
{
Uri baseAddr = new Uri("http://localhost:8000/WCFService1");
ServiceHost localHost = new ServiceHost(typeof(CalculatorService), baseAddr);

try
{
localHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(),
"CalculatorService");

ServiceMetadataBehavior smb = new ServiceMetadataBehavior();


smb.HttpGetEnabled = true;
localHost.Description.Behaviors.Add(smb);

localHost.Open();
Console.WriteLine("Service initialized.");
Console.WriteLine("Press the ENTER key to terminate service.");
Console.WriteLine();
Console.ReadLine();

localHost.Close();
}
catch (CommunicationException ex)
{
Console.WriteLine("Oops! Exception: {0}", ex.Message);
localHost.Abort();
}
}
}

Now our service is pretty much complete and ready to be consumed. Our Entire Service
code looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ServiceModel;
using System.ServiceModel.Description;

namespace ProgrammingHelp.WCFService1
{
[ServiceContract(Namespace = "http://ProgrammingHelp.Service/")]
public interface ICalculator
{
[OperationContract]
Double Add(Double n1, Double n2);
[OperationContract]
Double Subtract(Double n1, Double n2);
[OperationContract]
Double Multiply(Double n1, Double n2);
[OperationContract]
Double Divide(Double n1, Double n2);
}

class CalculatorService : ICalculator


{
public Double Add(Double num1, Double num2)
{
Double answer = num1 + num2;
Console.WriteLine("Call made: Add({0},{1})", num1, num2);
Console.WriteLine("Answer: {0}", answer);
return answer;
}

public Double Subtract(Double num1, Double num2)


{
Double answer = num1 - num2;
Console.WriteLine("Call made: Subtract({0},{1})", num1, num2);
Console.WriteLine("Answer: {0}", answer);
return answer;
}

public Double Multiply(Double num1, Double num2)


{
Double answer = num1 * num2;
Console.WriteLine("Call made: Multiply({0},{1})", num1, num2);
Console.WriteLine("Answer: {0}", answer);
return answer;
}

public Double Divide(Double num1, Double num2)


{
Double answer = num1 / num2;
Console.WriteLine("Call made: Divide({0},{1})", num1, num2);
Console.WriteLine("Answer: {0}", answer);
return answer;
}
}

class Program
{
static void Main(string[] args)
{
Uri baseAddr = new Uri("http://localhost:8000/WCFService1");
ServiceHost localHost = new ServiceHost(typeof(CalculatorService), baseAddr);

try
{
localHost.AddServiceEndpoint(typeof(ICalculator), new WSHttpBinding(),
"CalculatorService");

ServiceMetadataBehavior smb = new ServiceMetadataBehavior();


smb.HttpGetEnabled = true;
localHost.Description.Behaviors.Add(smb);

localHost.Open();
Console.WriteLine("Service initialized.");
Console.WriteLine("Press the ENTER key to terminate service.");
Console.ReadLine();

localHost.Close();
}
catch (CommunicationException ex)
{
Console.WriteLine("Oops! Exception: {0}", ex.Message);
localHost.Abort();
}
}
}
}
Server Intellect offers Windows Hosting Dedicated Servers at affordable prices. I'm very
pleased!

We will create our Client in a new Project, but within the same Solution as the Service.
To do this, right-click the Solution in Solution Explorer, and choose Add > New Project..
Console Application. Name it ClientApp. As with the Service, add a reference to the
System.ServiceModel.dll and a using directive.
Next, run the service from Visual Studio (hit F5), and then we need to goto the Start
Menu > All Programs > Microsoft Windows SDK > CMD Shell. If you do not have this,
then you will need to download the Windows SDK at the link at the top of this article.
You should have something like this:

[Click to see full-size]

Now we want to navigate to our ClientApp folder using cd (Change Directory). Example,
input cd "C:\Users\xxxxxx\Visual Studio
2008\Documents\Consoles\WCFService1\ClientApp" and hit Enter:

[Click to see full-size]

Finally, enter the following to generate the necessary files for our Client and then hit
Enter:
svcutil.exe /language:cs /out:generatedProxy.cs /config:app.config
http://localhost:8000/WCFService1
This will generate our Client files.
[Click to see full-size]

You can now close the CMD Shell window. Navigate to your ClientApp folder and
verify that the files were created in the correct location. You should now have app.config
and generatedProxy.cs.
We can now also terminate the Service and go back into Visual Studio. In Solution
Explorer, right-click the ClientApp project and choose to Add > Existing Item. Enter * in
the File name box and hit enter. There, choose to add the generatedProxy.cs and the
app.config we just created. The App.config file should look something like this:

<?xml version="1.0" encoding="utf-8"?>


<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_ICalculator" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false"
hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192"
maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="true" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8000/WCFService1/CalculatorService"
binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_ICalculator"
contract="ICalculator" name="WSHttpBinding_ICalculator">
<identity>
<userPrincipalName value="David.Lewis@clientintellect.local" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>

We are using Server Intellect and have found that by far, they are the most friendly,
responsive, and knowledgeable support team we've ever dealt with!

Notice the EndPoint was generated for our Client.


The generatedProxy.cs includes our interface and all of our methods:

//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.3074
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel",
"3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace="http://ProgrammingHelp.S
ervice/", ConfigurationName="ICalculator")]
public interface ICalculator
{
[System.ServiceModel.OperationContractAttribute(Action="http://ProgrammingHelp.Ser
vice/ICalculator/Add",
ReplyAction="http://ProgrammingHelp.Service/ICalculator/AddResponse")]
double Add(double n1, double n2);

[System.ServiceModel.OperationContractAttribute(Action="http://ProgrammingHelp.Ser
vice/ICalculator/Subtract",
ReplyAction="http://ProgrammingHelp.Service/ICalculator/SubtractResponse")]
double Subtract(double n1, double n2);

[System.ServiceModel.OperationContractAttribute(Action="http://ProgrammingHelp.Ser
vice/ICalculator/Multiply",
ReplyAction="http://ProgrammingHelp.Service/ICalculator/MultiplyResponse")]
double Multiply(double n1, double n2);

[System.ServiceModel.OperationContractAttribute(Action="http://ProgrammingHelp.Ser
vice/ICalculator/Divide",
ReplyAction="http://ProgrammingHelp.Service/ICalculator/DivideResponse")]
double Divide(double n1, double n2);
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel",
"3.0.0.0")]
public interface ICalculatorChannel : ICalculator, System.ServiceModel.IClientChannel
{
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel",
"3.0.0.0")]
public partial class CalculatorClient : System.ServiceModel.ClientBase<ICalculator>,
ICalculator
{
public CalculatorClient()
{
}

public CalculatorClient(string endpointConfigurationName) :


base(endpointConfigurationName)
{
}

public CalculatorClient(string endpointConfigurationName, string remoteAddress) :


base(endpointConfigurationName, remoteAddress)
{
}

public CalculatorClient(string endpointConfigurationName,


System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}
public CalculatorClient(System.ServiceModel.Channels.Binding binding,
System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}

public double Add(double n1, double n2)


{
return base.Channel.Add(n1, n2);
}

public double Subtract(double n1, double n2)


{
return base.Channel.Subtract(n1, n2);
}

public double Multiply(double n1, double n2)


{
return base.Channel.Multiply(n1, n2);
}

public double Divide(double n1, double n2)


{
return base.Channel.Divide(n1, n2);
}
}

We chose Server Intellect for its dedicated servers, for our web hosting. They have
managed to handle virtually everything for us, from start to finish. And their customer
service is stellar.

Finally, we can add the logic to our Client Program.cs, which will interact with the
Service, using the methods. We call each method with parameters for the Service to
calculate and then return the answers back to the Client:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ServiceModel;

namespace ProgrammingHelp.ClientApp
{
class ClientApp
{
static void Main(string[] args)
{
CalculatorClient client = new CalculatorClient();

double value1 = 100.00D;


double value2 = 15.99D;
double result = client.Add(value1, value2);
Console.WriteLine("{0} + {1} = {2}", value1, value2, result);

value1 = 145.00D;
value2 = 76.54D;
result = client.Subtract(value1, value2);
Console.WriteLine("{0} - {1} = {2}", value1, value2, result);

value1 = 9.00D;
value2 = 81.25D;
result = client.Multiply(value1, value2);
Console.WriteLine("{0} x {1} = {2}", value1, value2, result);

value1 = 22.00D;
value2 = 7.00D;
result = client.Divide(value1, value2);
Console.WriteLine("{0} / {1} = {2}", value1, value2, result);

client.Close();

Console.WriteLine();
Console.WriteLine("Press the ENTER key to terminate client.");
Console.ReadLine();
}
}
}

To test the client, right-click on the Service project in Solution Explorer, and choose
rebuild. Then do the same for the Client. Now we can goto the bin/debug/ folder of each
project and first run the WCFService1.exe to initialize, and then the ClientApp.exe. We
should have an output like this:
[Click to see full-size]

WCF Tutorial - Basic Interprocess


Communication
Posted in:

• Tutorials
• .NET
• WCF
• .NET 3.5
• C#

Related Posts

• WCF Tutorial - Events and Callbacks


• WCF Snippet Tutorial - Overloading Methods
• WCF Tip: Using Properties in Service Contracts
• WCF Callbacks Hanging WPF Applications

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;
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;
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.

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")
}))
{

}
}
}
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.

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();
}
}
}

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;
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;
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.

string str = Console.ReadLine();


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;
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));
}
}
}
}

Introduction

This is a simple working Real-Time data publisher written in C# NET 3.5. It is composed
of two pieces, a server WCF console and a WPF client. It demonstrates a simple way of
maintaining a persisted callback to multiple clients. Each client subscription is
maintained by the server console.

The code demonstrates an implementation of the following:

• Publish / Subscribe Implementation (not events)


• ClientCallback subscription
• Fake Tick Plant
• Data Dictionary
• Multi-Threading
• Object Serialization
How to Run

There are two working executables in this project, a WCF console


(WCFMarketDataServer.exe) and a WPF client (WFCTickerWindow.exe).

First start the WCF console. You can only have one instance running. The server is ready
once you see the "press any key" prompt:
Now you can start the client. You can start as many clients as you want to simulate
multiple users. Each client should maintain its own set of real time data.

As you change the preset value on the combo boxes, a subscription / un-subscription
requests will be processed by the server to maintain the proper data each to which each
client is subscribed.

Using the Code

Below, find an overview of the main class structure. I am not going into much detail but
it shows how the main data flows and the subscription mechanism is working.
The WCF server console is configured programmatically utilizing a TCP channel.

Collapse
// Service htpp address
CMarkerConfig.LogInfo("Creating URI...");
Uri baseAddress = new Uri("net.tcp://localhost:8080/MarketData");
// Create new WCF Service host
CMarkerConfig.LogInfo("Creating ServiceHost...");
serviceHost = new ServiceHost(typeof(CMarketDataManager),
baseAddress);

// Add the htpp end point


NetTcpBinding pNetTcpBinding = new
NetTcpBinding(SecurityMode.Transport);

CMarkerConfig.LogInfo("Adding Endpoint...");
serviceHost.AddServiceEndpoint(typeof(IMarketData), pNetTcpBinding,
baseAddress);

// Add the Metadata


CMarkerConfig.LogInfo("Adding Metadata behavior...");
ServiceMetadataBehavior servicemetadatabehavior = new
ServiceMetadataBehavior();
servicemetadatabehavior.HttpGetEnabled = true;
servicemetadatabehavior.HttpGetUrl = new
Uri("http://localhost:8081/MarketData");
serviceHost.Description.Behaviors.Add(servicemetadatabehavior);

Following is the service contact:

Collapse
//-----------------------------------------------------------------
-----------------
/// <summary>
/// Callback contract to update clients with TickUpdate data stream.
/// </summary>

interface IClientCallback
{
//-------------------------------------------------------------
[OperationContract(IsOneWay = true)]
void SendTickUpdate(TickUpdate pTickUpdate);
}

//-----------------------------------------------------------------
------------------
/// <summary>
/// WCF Contracts for client interaction with this service
/// </summary>
[ServiceContract(Namespace = "tcp://localhost/", CallbackContract =
typeof(
IClientCallback))]
interface IMarketData
{
//-------------------------------------------------------------
[OperationContract]
string[] GetSymbolList();

//-------------------------------------------------------------
[OperationContract]
StringCollection GetDataSourceList();

//-------------------------------------------------------------
[OperationContract]
string[] GetFieldList();

//-------------------------------------------------------------
[OperationContract]
void SubscribeRT(CGenericMsg pCGenericMsg);
}

Potrebbero piacerti anche