Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Basic Step by Step WCF WebService

4.78/5 (62 votes)
14 Feb 2016CPOL5 min read 267.6K  
Basic steps in creating and consuming a simple WCF web service.

Introduction

In this article, I will be creating a simple Student Enrollment web service using WCF components from the ground up. This article does not use the WCF Project template in Visual Studio rather I will create this WCF web service using basic components that builds up the WCF technology. I will break down the components into separate discrete assemblies to give you a wider view of the big picture of WCF. Then, I will host this web service in a simple Console Application. Finally, I will consume the web service through a WPF application client.

Background

WCF is a unification of multiple technologies that were used in creating Distributed Applications which includes COM+, .NET Enterprise Services, MSMQ, .NET Remoting, Web services, etc. for communication. Hence, WCF is a vast topic to tackle in just one article. Because of this, you should be aware that this article only introduces you to a small part of the capability of WCF. However this article will try to demonstrate the most basic building blocks and architecture of WCF.

More of that, it would be much easier to grasp a topic if we can just create and test it, right? So let's dive into the code project!

Using the code

(Note: This project will use a Console Application to host the web service for simplicity. There are multiple ways to host a WCF web service. Please refer to other articles that discusses this part. Also note that this project uses Web Service Binding, specifically wsHTTPBinding. There are also many types of bindings to choose from that are not discussed in this article.)

First step - Define the WebService Interface

Image 1

Tip 1: In this article I am just creating one interface for our service but you can actually create as many interfaces as you want in your desired project.

Tip  2: Interfaces contain the signatures of the operations, messages and data that the client can use to communicate with the server.  

Image 2

  • Open Visual Studio 2010 and create a new project. Select Class Library project and name it BasicWCFWebService. Note: I am creating a Class Library for the WebService interface to decouple it from the service host logic and make it generally usable for both the client and host application.
  • A default class file Class1.cs is generated. Rename this file to IStudentEnrollmentService.cs. This file will contain the "Interface" that is exposed by this service. Also rename the first project to SchoolServiceInterfaces
  • In Solution Explorer, right click on the References folder and then click Add Reference. In the .NET tab, select System.ServiceModel and System.Runtime.Serialization assemblies, finally click the OK button.
    • System.ServiceModel contains the ServiceContractAttribute attribute definition
    • System.Runtime.Serialization contains the DataContractAttribute attribute definition
  • After adding the latter assembly references, include these in the code by adding using statements for both System.ServiceModel and System.Runtime.Serialization namespaces.

IStudentEnrollmentService.cs

C#
using System;
using System.Collections.Generic;
using System.Text;

using System.ServiceModel;
using System.Runtime.Serialization;

namespace SchoolServiceInterfaces 
{
    [ServiceContract]
    public interface IStudentEnrollmentService
    {
        [OperationContract]
        void EnrollStudent(Student s);

        [OperationContract]
        Student[] GetEnrolledStudents();
    }

    [DataContract]
    public class Student
    {
        private string name;

        [DataMember]
        public string StudentName
        {
            set { this.name = value; }
            get { return this.name; }
        }
    }
}

Second Step - Create a database "mock up" class

Create a new Class Library project and name it SchoolDatabase.cs.

Tip 3: This is just a mock up database project. You can create or use the real database objects on your real project. This is the reason why we created a separate project for the database so that we can emulate a real world database architecture. Remember that a database is a separate entity and not bound to our project.

Image 3

StudentDatabase.cs

C#
using System;
using System.Collections.Generic;
using System.Text;

namespace SchoolDatabase
{
    public class StudentDatabase
    {
        private static List<string> studentData = new List<string>();

        public void AddStudent(string studentName)
        {
            studentData.Add(studentName);
        }

        public List<string> GetStudentList()
        {
            return studentData;
        }
    }
}

Third step - Implement the web service interface

Image 4

  • Create a new Class Library project and name it SchoolServices and rename Class1.cs to StudentEnrollmentService.cs. Then, add references to the SchoolDatabase and SchoolServiceInterfaces projects. To do this, right click on the References folder in the SchoolServices project then on the "Project" tab, select the SchoolDatabase and StudentServiceInterfaces projects.
  • Implement the IStudentEnrollmentService interface and use the StudentDatabase class to store student information.

StudentEnrollmentService.cs

C#
using System;
using System.Collections.Generic;
using System.Text;

using SchoolServiceInterfaces;
using SchoolDatabase;

namespace SchoolServices
{
    public class StudentEnrollmentService : IStudentEnrollmentService
    {
        public void EnrollStudent(Student s)
        {
            StudentDatabase sd = new StudentDatabase();
            sd.AddStudent(s.StudentName);
        }

        public Student[] GetEnrolledStudents()
        {
            StudentDatabase sd = new StudentDatabase();
            List<string>studentList = sd.GetStudentList();
            Student[] studentArray = new Student[studentList.Count];
            for (int i = 0; i < studentList.Count; i++)
            {
                Student s = new Student();
                s.StudentName = studentList[i];
                studentArray[i] = s;
            }
            return studentArray;
        }
    }
}

Fourth step - Host the web service

  • To run the web service we must host it. In this article we will just use a simple Console Application to host our web service.
  • To do this, create a new Console Application project and name it SchoolServiceHost. Then add references to .NET System.ServiceModel and to our projects SchoolServices and SchoolServiceInterfacesSystem.ServiceModel is a .Net component that contains the base mechanism of a .Net web service, in this case, to create a Service host by using ServiceHost. I suggest you read more about System.ServiceModel namespace.

Image 5

Program.cs

XML
using System;
using System.Collections.Generic;
using System.Text;

using System.ServiceModel;
using SchoolServices;

namespace SchoolServiceHost
{
    class Program
    {
        static ServiceHost host = null;

        static void StartService()
        {
            host = new ServiceHost(typeof(StudentEnrollmentService)); 
	    /***********
	     * if you don't want to use App.Config for the web service host, 
             * just uncomment below:
	     ***********
             host.AddServiceEndpoint(new ServiceEndpoint(
             ContractDescription.GetContract(typeof(IStudentEnrollmentService)),
             new WSHttpBinding(), 
             new EndpointAddress("http://localhost:8732/awesomeschoolservice"))); 
	     **********/
            host.Open();
        }

        static void CloseService()
        {
            if (host.State != CommunicationState.Closed)
            {
                host.Close();
            }
        }

        static void Main(string[] args)
        {
            StartService();

            Console.WriteLine("Student Enrollment Service is running....");
            Console.ReadKey();

            CloseService();
        }
    }
} 

Add App.config file to the SchoolServiceHost project. This will contain the ABC information of our WCF web service which are:

  • "A" for "Address" - where to access the service. This defines the endpoint information where the service is located or accessible.
  • "B" for "Binding" - how to access the service. This defines the transport protocol that should be used to access this service.
  • "C" for "Contract" - what to access in the service. This defines the services offered by this web service.

Image 6

App.config

XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <!-- Server Configuration -->
  <system.serviceModel>
    <services>
      <service name="SchoolServices.StudentEnrollmentService">
        <endpoint 
		address="http://localhost:8732/awesomeschoolservice" 
		binding="wsHttpBinding" 
		contract="SchoolServiceInterfaces.IStudentEnrollmentService" />
      </service>
    </services>
  </system.serviceModel>
</configuration> 

Fifth step - Consuming the web service through a WPF client

Add a new WPF Application project and name it SchoolServiceClient. Then add references to System.ServiceModel and SchoolServiceInterfaces.

Image 7

Tip 4: Client only needs to know the signature of our service, it doesn't need to know the implementation or how the service implemented those services that is why we will only add the reference of SchoolServiceInterfaces which contains the contract of the web service we are interested to. System.ServiceModel is a .Net component that contains the base mechanism of a .Net web service, in this case, to create a Service client by using ChannelFactory. I suggest you read more about System.ServiceModel namespace.

MainWindow.xaml

Image 8

XML
<Window x:Class="SchoolServiceClient.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="296" Width="293">
    <Grid>
        <Button Content="Enroll" Height="23" HorizontalAlignment="Left" Margin="184,12,0,0" 
		Name="enrollBtn" VerticalAlignment="Top" Width="75" Click="enrollBtn_Click" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="studentNameTxt" 
		VerticalAlignment="Top" Width="152" />
        <Button Content="Get Enrolled Students" Height="23" HorizontalAlignment="Left" Margin="136,222,0,0" 
		Name="getEnrollBtn" VerticalAlignment="Top" Width="123" Click="getEnrollBtn_Click" />
        <TextBox Height="165" HorizontalAlignment="Left" Margin="12,51,0,0" Name="enrolledTxt" 
		VerticalAlignment="Top" Width="247" />
    </Grid>
</Window>

MainWindow.cs

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

using System.ServiceModel;
//contains the signature(message, data, operation)
//of the web service
using SchoolServiceInterface;

namespace SchoolServiceClient
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void enrollBtn_Click(object sender, RoutedEventArgs e)
        {
            if (studentNameTxt.Text == "") return;

            using (ChannelFactory<IStudentEnrollmentService> schoolServiceProxy = 
			new ChannelFactory<IStudentEnrollmentService>("MyStudentEnrollmentServiceEndpoint"))
            {
                schoolServiceProxy.Open();
                IStudentEnrollmentService schoolEnrollmentService = schoolServiceProxy.CreateChannel();
                Student s = new Student();
                s.StudentName = studentNameTxt.Text;
                schoolEnrollmentService.EnrollStudent(s);
                schoolServiceProxy.Close();
            }

            studentNameTxt.Text = "";
        }

        private void getEnrollBtn_Click(object sender, RoutedEventArgs e)
        {
            enrolledTxt.Text = "";
            using (ChannelFactory<IStudentEnrollmentService> schoolServiceProxy = 
			new ChannelFactory<IStudentEnrollmentService>("MyStudentEnrollmentServiceEndpoint"))
            {
                schoolServiceProxy.Open();
                IStudentEnrollmentService schoolEnrollmentService = schoolServiceProxy.CreateChannel();
                Student[] enrolledStudents = schoolEnrollmentService.GetEnrolledStudents();
                foreach (Student s in enrolledStudents)
                {
                    enrolledTxt.AppendText(s.StudentName + "\n");
                }
                schoolServiceProxy.Close();
            }
        }
    }
}

App.config

XML
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <!-- Client Configuration -->
  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="WSHttpBinding_IStudentEnrollmentService" />
      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://localhost:8732/awesomeschoolservice"
          binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IStudentEnrollmentService"
          contract="SchoolServiceInterfaces.IStudentEnrollmentService" name="MyStudentEnrollmentServiceEndpoint">
      </endpoint>
    </client>
  </system.serviceModel>
</configuration>

Sixth Step - Run and test the web service

  • Build the solution, then go to the output directories of SchoolServiceHost and SchoolServiceClient. First run SchoolServiceHost.exe, then SchoolServiceClient.exe, respectively.

Image 9

Points of interest

Decoupling components greatly improves maintainability, scalability, and stability of an application. This topic demonstrates the most basic parts of a WCF application rather than using a template. Building these small parts gives you flexibility and an in-depth understanding of its underlying technologies. You should now be able to create more advanced WCF applications using the very basic understanding of its architecture and its building blocks. 

Your feedback is always welcome.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)