Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WinForms

A Quick and Dirty WCF Service and Client (Using WCF and Winforms)

4.91/5 (27 votes)
14 May 20077 min read 3   4.5K  
An example of how to use Windows Communication Foundation services.

Introduction

This is a complete walk-through of creating a self-hosted WCF Service and Client. You will need .NET 3.0 and Visual Studio 2005 in order to get this to work.

Example WCF Service

Getting Started

Open Visual Studio 2005 and create a new WCF Service Library project. This project type is listed under NET Framework 3.0. This will create a project and a C# file (Class1.cs). The C# file contains a service stub that we will modify.

Modifying the Service

First we will change the data contract class near the bottom of the page. It starts off looking like this:

C#
[DataContract]
public class DataContract1
{
    string firstName;
    string lastName;

    [DataMember]
    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }
    [DataMember]
    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }
}

All we are going to do is change the class name. Change the class name to "Patient" now.

Data Contract definition

A data contract is a formal agreement between a service and a client that abstractly describes the data to be exchanged. That is, in order to communicate, the client and the service do not have to share the same types, only the same data contracts. A data contract precisely defines, for each parameter or return type, what data is serialized (turned into XML) in order to be exchanged. (Microsoft)

Next we need to change the service contract interface.

Service Contract definition

Service contracts express valid message exchange patterns between two parties. The party that initiates communication is called the initiator. The other party is called the service. Service contracts specify one or more operation contracts. An operation contract represents an individual message exchange or a correlated request/reply message exchange. (Don Box)

The service contract's name is fine, but let's change the methods marked with the [OperationContract] attribute to Get and Set methods for our Patient class (data contract).

C#
[ServiceContract()]
public interface IService1
{
    [OperationContract]
    Patient GetPatient(Int32 index);

    [OperationContract]
    void SetPatient(Int32 index, Patient patient);
}

The index parameter to the above methods will be used to access a single Patient in an array of Patients. This will become obvious after we modify the IService1 implementation class next. Replace the service1 class with the following code:

C#
[ServiceBehavior(IncludeExceptionDetailInFaults=true)]
public class PatientService : IService1
{
    Patient[] pat = null;

    public PatientService()
    {
        pat = new Patient[3];

        pat[0] = new Patient();
        pat[0].FirstName = "Bob";
        pat[0].LastName = "Chandler";

        pat[1] = new Patient();
        pat[1].FirstName = "Joe";
        pat[1].LastName = "Klink";

        pat[2] = new Patient();
        pat[2].FirstName = "Sally";
        pat[2].LastName = "Wilson";
    }

    public Patient GetPatient(Int32 index)
    {
        if (index <= pat.GetUpperBound(0) && index > -1)
            return pat[index];
        else
            return new Patient();
    }

    public void SetPatient(Int32 index, Patient patient)
    {
        if (index <= pat.GetUpperBound(0) && index > -1)
            pat[index] = patient;
    }
}

The ServiceBehavior attribute, IncludeExceptionDetailInFaults=true, will give us more detailed error information while debugging if we mess something up. Without this we get a generic FaultException that tells us nothing about the real error.

The constructor of our PatientService class creates and fills our Patient array.
The GetPatient method returns the Patient object at index.
The SetPatient method sets the Patient object at index to the Patient object passed in via the second parameter.

Now we should have a working service but we need a host for our service to reside in.

The Service Host

Right-click on the service project and go to Properties. Change the Output Type from Class Library to Windows Application.

Close the properties Window and right-click the project again and this time choose Add, New Item, choose Windows Form and click the Add button.

In the form Designer add a single button and double-click the newly added button. This will add a click event handler and move you to the code window.

Add a using System.ServiceModel; up at the top. This will allow us to host our service.

Then, right above the Form1 constructor, add 2 new class variables.

C#
bool serviceStarted = false;
ServiceHost myServiceHost = null;
Now back to the button1_Click event handler code. Make the code listed below your method body.
C#
if (serviceStarted)
{
    myServiceHost.Close();
    serviceStarted = false;
    button1.Text = "Start Service";
}
else
{
    Uri baseAddress = new Uri("net.tcp://localhost:2202/PatientService");

    NetTcpBinding binding = new NetTcpBinding();

    myServiceHost = new ServiceHost(typeof(PatientService), baseAddress);
    myServiceHost.AddServiceEndpoint(typeof(IService1), binding, baseAddress);

    myServiceHost.Open();

    serviceStarted = true;
    button1.Text = "Stop Service";
}

What this bit of code does is startup a host for our service if its not started already, or closes the host if it is started.

To host or start a service you have to know your ABC's. Not the alphabet, but the service's Address, Binding, and Contract.

In this case, we pretty much make up an address. We'll use TCP binding (method of communication) so the first part of the address (URI) is set to net.tcp. The next part of the address is the machine name or IP and port number. Localhost just means your machine and the port number (2202) was just arbitrary. You will need to make sure its a valid and open port before just choosing any number. The last part of the address is just our service name.

The binding is TCP so we need to make a NetTcpBinding object.

Our contract is IService1, the name of our service contract interface.

We create a new ServiceHost object which takes a "singletonInstance" type and our Address as parameters. The "singletonInstance" is our contract's implementation class, PatientService.

Next we add an Endpoint to the host we just created. This takes our ABC's as parameters, but in reverse order for some reason.

The host is Opened or Closed to allow clients access or not respectively.

We need to add a main entry point to our host application so at the bottom, right below the class but inside the namespace brackets, add the following code.

C#
static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }
}

Go ahead back to the form designer and change the text on the button to "Start Service".

You can build and run this application if you want to now. You have now finished a self-hosted service, but we need a client to consume the service.

Example Client

Right-click on the solution and click Add, New Project, Windows, and choose Windows Application.

Add 3 label controls, 3 textboxes, and 2 buttons to the new Form.

  • Change label1's text property to "Index:"
  • Change label2's text property to "First Name:"
  • Change label3's text property to "Last Name:"
  • Change button1's text property to "Get Patient"
  • Change button2's text property to "Set Patient"
  • Line up textBox1 and button1 to label1
  • Line up textBox2 and button2 to label2
  • Finally, line up textBox3 to label3

The end product should look like this:

Screenshot - Image1.jpg

Now double-click a blank part of the form to add a Load event handler for the form. Then double-click both of the buttons to add click event handlers for each.

We need to add 2 references to the client project. Select the Project menu item and click Add Reference. Under the .NET tab, find and select System.ServiceModel and click OK. Add another reference, this time choose the Projects tab and select your service that you made earlier.

Back in Form1.cs, add using System.ServiceModel; and using YourService; (replace YourService with the name of your service) to the list of other usings.

Now we're ready to access our service. Add a class variable right above the constructor called IService1 patientSvc and set it to null. Like in our host application we have to use our ABC's to setup an Endpoint to our service. In the Form1_Load event handler, add the following code:

C#
EndpointAddress address = new EndpointAddress
            (new Uri("net.tcp://localhost:2202/PatientService"));
NetTcpBinding binding = new NetTcpBinding();
ChannelFactory<iservice1 /><IService1> factory = 
            new ChannelFactory<iservice1 /><IService1>(binding, address);
patientSvc = factory.CreateChannel();</iservice1 /></iservice1 />

This code creates a new IService1 object in the form of our PatientService class, again using the service contract's ABC's. Microsoft defines a ChannelFactory as... A factory that creates channels of different types that are used by clients to send messages to variously configured service endpoints. So now we have a PatientService (IService1) object, which is all we need to know at this point.

Put the following code into the button click handlers:

C#
private void button1_Click(object sender, EventArgs e)
{
    Patient patient = patientSvc.GetPatient(Convert.ToInt32(textBox1.Text));

    if (patient != null)
    {
        textBox2.Text = patient.FirstName;
        textBox3.Text = patient.LastName;
    }
}

private void button2_Click(object sender, EventArgs e)
{
    Patient patient = new Patient();
    patient.FirstName = textBox2.Text;
    patient.LastName = textBox3.Text;

    patientSvc.SetPatient(Convert.ToInt32(textBox1.Text), patient);
}

When button1 is clicked, it takes the index entered in textBox1, converts it to an Int32, and passes it to our GetPatient method in our PatientService. What returns is a full-fledged Patient object if the index is valid (null otherwise). This is the same Patient object that we defined in our DataContract class in our service. We then fill the other 2 textboxes with the first and last names.

When button2 is clicked, we create a new Patient object, fill its 2 properties with values from our textboxes and then set the Patient at index in our PatientService to this new Patient.

Conclusion

That's it! We now have a working self-hosted WCF service and client. Right-click on the solution and choose Set Startup Projects, then choose Multiple Startup Projects. Set the Action on both projects to Start, then click OK. Now debug the solution and the service host and the client will both be running. Make sure to click the Start Service button before attempting to click any buttons on the client.

History

  • May 14, 2007: Version 1.0 uploaded
  • May 17th, 2007: Fixed article mistake in client ChannelFactory settings

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here